• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for generating and processing CoAP messages.
32  */
33 
34 #ifndef COAP_HEADER_HPP_
35 #define COAP_HEADER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/coap.h>
40 
41 #include "common/as_core_type.hpp"
42 #include "common/clearable.hpp"
43 #include "common/code_utils.hpp"
44 #include "common/const_cast.hpp"
45 #include "common/encoding.hpp"
46 #include "common/message.hpp"
47 #include "net/ip6.hpp"
48 #include "net/ip6_address.hpp"
49 #include "net/udp6.hpp"
50 #include "thread/uri_paths.hpp"
51 
52 namespace ot {
53 
54 /**
55  * @namespace ot::Coap
56  * @brief
57  *   This namespace includes definitions for CoAP.
58  */
59 namespace Coap {
60 
61 /**
62  * @addtogroup core-coap
63  *
64  * @brief
65  *   This module includes definitions for CoAP.
66  *
67  * @{
68  */
69 
70 class Option;
71 
72 /**
73  * CoAP Type values.
74  */
75 enum Type : uint8_t
76 {
77     kTypeConfirmable    = OT_COAP_TYPE_CONFIRMABLE,     ///< Confirmable type.
78     kTypeNonConfirmable = OT_COAP_TYPE_NON_CONFIRMABLE, ///< Non-confirmable type.
79     kTypeAck            = OT_COAP_TYPE_ACKNOWLEDGMENT,  ///< Acknowledgment type.
80     kTypeReset          = OT_COAP_TYPE_RESET,           ///< Reset type.
81 };
82 
83 /**
84  * CoAP Code values.
85  */
86 enum Code : uint8_t
87 {
88     // Request Codes:
89 
90     kCodeEmpty  = OT_COAP_CODE_EMPTY,  ///< Empty message code
91     kCodeGet    = OT_COAP_CODE_GET,    ///< Get
92     kCodePost   = OT_COAP_CODE_POST,   ///< Post
93     kCodePut    = OT_COAP_CODE_PUT,    ///< Put
94     kCodeDelete = OT_COAP_CODE_DELETE, ///< Delete
95 
96     // Response Codes:
97 
98     kCodeResponseMin = OT_COAP_CODE_RESPONSE_MIN, ///< 2.00
99     kCodeCreated     = OT_COAP_CODE_CREATED,      ///< Created
100     kCodeDeleted     = OT_COAP_CODE_DELETED,      ///< Deleted
101     kCodeValid       = OT_COAP_CODE_VALID,        ///< Valid
102     kCodeChanged     = OT_COAP_CODE_CHANGED,      ///< Changed
103     kCodeContent     = OT_COAP_CODE_CONTENT,      ///< Content
104     kCodeContinue    = OT_COAP_CODE_CONTINUE,     ///< RFC7959 Continue
105 
106     // Client Error Codes:
107 
108     kCodeBadRequest         = OT_COAP_CODE_BAD_REQUEST,         ///< Bad Request
109     kCodeUnauthorized       = OT_COAP_CODE_UNAUTHORIZED,        ///< Unauthorized
110     kCodeBadOption          = OT_COAP_CODE_BAD_OPTION,          ///< Bad Option
111     kCodeForbidden          = OT_COAP_CODE_FORBIDDEN,           ///< Forbidden
112     kCodeNotFound           = OT_COAP_CODE_NOT_FOUND,           ///< Not Found
113     kCodeMethodNotAllowed   = OT_COAP_CODE_METHOD_NOT_ALLOWED,  ///< Method Not Allowed
114     kCodeNotAcceptable      = OT_COAP_CODE_NOT_ACCEPTABLE,      ///< Not Acceptable
115     kCodeRequestIncomplete  = OT_COAP_CODE_REQUEST_INCOMPLETE,  ///< RFC7959 Request Entity Incomplete
116     kCodePreconditionFailed = OT_COAP_CODE_PRECONDITION_FAILED, ///< Precondition Failed
117     kCodeRequestTooLarge    = OT_COAP_CODE_REQUEST_TOO_LARGE,   ///< Request Entity Too Large
118     kCodeUnsupportedFormat  = OT_COAP_CODE_UNSUPPORTED_FORMAT,  ///< Unsupported Content-Format
119 
120     // Server Error Codes:
121 
122     kCodeInternalError      = OT_COAP_CODE_INTERNAL_ERROR,      ///< Internal Server Error
123     kCodeNotImplemented     = OT_COAP_CODE_NOT_IMPLEMENTED,     ///< Not Implemented
124     kCodeBadGateway         = OT_COAP_CODE_BAD_GATEWAY,         ///< Bad Gateway
125     kCodeServiceUnavailable = OT_COAP_CODE_SERVICE_UNAVAILABLE, ///< Service Unavailable
126     kCodeGatewayTimeout     = OT_COAP_CODE_GATEWAY_TIMEOUT,     ///< Gateway Timeout
127     kCodeProxyNotSupported  = OT_COAP_CODE_PROXY_NOT_SUPPORTED, ///< Proxying Not Supported
128 };
129 
130 /**
131  * CoAP Option Numbers.
132  */
133 enum OptionNumber : uint16_t
134 {
135     kOptionIfMatch       = OT_COAP_OPTION_IF_MATCH,       ///< If-Match
136     kOptionUriHost       = OT_COAP_OPTION_URI_HOST,       ///< Uri-Host
137     kOptionETag          = OT_COAP_OPTION_E_TAG,          ///< ETag
138     kOptionIfNoneMatch   = OT_COAP_OPTION_IF_NONE_MATCH,  ///< If-None-Match
139     kOptionObserve       = OT_COAP_OPTION_OBSERVE,        ///< Observe [RFC7641]
140     kOptionUriPort       = OT_COAP_OPTION_URI_PORT,       ///< Uri-Port
141     kOptionLocationPath  = OT_COAP_OPTION_LOCATION_PATH,  ///< Location-Path
142     kOptionUriPath       = OT_COAP_OPTION_URI_PATH,       ///< Uri-Path
143     kOptionContentFormat = OT_COAP_OPTION_CONTENT_FORMAT, ///< Content-Format
144     kOptionMaxAge        = OT_COAP_OPTION_MAX_AGE,        ///< Max-Age
145     kOptionUriQuery      = OT_COAP_OPTION_URI_QUERY,      ///< Uri-Query
146     kOptionAccept        = OT_COAP_OPTION_ACCEPT,         ///< Accept
147     kOptionLocationQuery = OT_COAP_OPTION_LOCATION_QUERY, ///< Location-Query
148     kOptionBlock2        = OT_COAP_OPTION_BLOCK2,         ///< Block2 (RFC7959)
149     kOptionBlock1        = OT_COAP_OPTION_BLOCK1,         ///< Block1 (RFC7959)
150     kOptionSize2         = OT_COAP_OPTION_SIZE2,          ///< Size2 (RFC7959)
151     kOptionProxyUri      = OT_COAP_OPTION_PROXY_URI,      ///< Proxy-Uri
152     kOptionProxyScheme   = OT_COAP_OPTION_PROXY_SCHEME,   ///< Proxy-Scheme
153     kOptionSize1         = OT_COAP_OPTION_SIZE1,          ///< Size1
154 };
155 
156 /**
157  * Implements CoAP message generation and parsing.
158  */
159 class Message : public ot::Message
160 {
161     friend class Option;
162     friend class MessageQueue;
163 
164 public:
165     static constexpr uint8_t kDefaultTokenLength = OT_COAP_DEFAULT_TOKEN_LENGTH; ///< Default token length.
166     static constexpr uint8_t kMaxReceivedUriPath = 32;                           ///< Max URI path length on rx msgs.
167     static constexpr uint8_t kMaxTokenLength     = OT_COAP_MAX_TOKEN_LENGTH;     ///< Maximum token length.
168 
169     typedef ot::Coap::Type Type; ///< CoAP Type.
170     typedef ot::Coap::Code Code; ///< CoAP Code.
171 
172     /**
173      * CoAP Block1/Block2 Types
174      */
175     enum BlockType : uint8_t
176     {
177         kBlockType1 = 1,
178         kBlockType2 = 2,
179     };
180 
181     static constexpr uint8_t kBlockSzxBase = 4;
182 
183     /**
184      * Initializes the CoAP header.
185      */
186     void Init(void);
187 
188     /**
189      * Initializes the CoAP header with specific Type and Code.
190      *
191      * @param[in]  aType  The Type value.
192      * @param[in]  aCode  The Code value.
193      */
194     void Init(Type aType, Code aCode);
195 
196     /**
197      * Initializes the CoAP header with specific Type and Code.
198      *
199      * @param[in]  aType              The Type value.
200      * @param[in]  aCode              The Code value.
201      * @param[in]  aUri               The URI.
202      *
203      * @retval kErrorNone         Successfully appended the option.
204      * @retval kErrorNoBufs       The option length exceeds the buffer size.
205      */
206     Error Init(Type aType, Code aCode, Uri aUri);
207 
208     /**
209      * Initializes the CoAP header as `kCodePost` with a given URI Path with its type determined from a
210      * given destination IPv6 address.
211      *
212      * @param[in]  aDestination       The message destination IPv6 address used to determine the CoAP type,
213      *                                `kTypeNonConfirmable` if multicast address, `kTypeConfirmable` otherwise.
214      * @param[in]  aUri               The URI.
215      *
216      * @retval kErrorNone         Successfully appended the option.
217      * @retval kErrorNoBufs       The option length exceeds the buffer size.
218      */
219     Error InitAsPost(const Ip6::Address &aDestination, Uri aUri);
220 
221     /**
222      * Writes header to the message. This must be called before sending the message.
223      *
224      * Also checks whether the payload marker is set (`SetPayloadMarker()`) but the message contains no
225      * payload, and if so it removes the payload marker from the message.
226      */
227     void Finish(void);
228 
229     /**
230      * Returns the Version value.
231      *
232      * @returns The Version value.
233      */
GetVersion(void) const234     uint8_t GetVersion(void) const
235     {
236         return (GetHelpData().mHeader.mVersionTypeToken & kVersionMask) >> kVersionOffset;
237     }
238 
239     /**
240      * Sets the Version value.
241      *
242      * @param[in]  aVersion  The Version value.
243      */
SetVersion(uint8_t aVersion)244     void SetVersion(uint8_t aVersion)
245     {
246         GetHelpData().mHeader.mVersionTypeToken &= ~kVersionMask;
247         GetHelpData().mHeader.mVersionTypeToken |= aVersion << kVersionOffset;
248     }
249 
250     /**
251      * Returns the Type value.
252      *
253      * @returns The Type value.
254      */
GetType(void) const255     uint8_t GetType(void) const { return (GetHelpData().mHeader.mVersionTypeToken & kTypeMask) >> kTypeOffset; }
256 
257     /**
258      * Sets the Type value.
259      *
260      * @param[in]  aType  The Type value.
261      */
SetType(Type aType)262     void SetType(Type aType)
263     {
264         GetHelpData().mHeader.mVersionTypeToken &= ~kTypeMask;
265         GetHelpData().mHeader.mVersionTypeToken |= (static_cast<uint8_t>(aType) << kTypeOffset);
266     }
267 
268     /**
269      * Returns the Code value.
270      *
271      * @returns The Code value.
272      */
GetCode(void) const273     uint8_t GetCode(void) const { return static_cast<Code>(GetHelpData().mHeader.mCode); }
274 
275     /**
276      * Sets the Code value.
277      *
278      * @param[in]  aCode  The Code value.
279      */
SetCode(Code aCode)280     void SetCode(Code aCode) { GetHelpData().mHeader.mCode = static_cast<uint8_t>(aCode); }
281 
282 #if OPENTHREAD_CONFIG_COAP_API_ENABLE
283     /**
284      * Returns the CoAP Code as human readable string.
285      *
286      * @ returns The CoAP Code as string.
287      */
288     const char *CodeToString(void) const;
289 #endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
290 
291     /**
292      * Returns the Message ID value.
293      *
294      * @returns The Message ID value.
295      */
GetMessageId(void) const296     uint16_t GetMessageId(void) const { return BigEndian::HostSwap16(GetHelpData().mHeader.mMessageId); }
297 
298     /**
299      * Sets the Message ID value.
300      *
301      * @param[in]  aMessageId  The Message ID value.
302      */
SetMessageId(uint16_t aMessageId)303     void SetMessageId(uint16_t aMessageId) { GetHelpData().mHeader.mMessageId = BigEndian::HostSwap16(aMessageId); }
304 
305     /**
306      * Returns the Token length.
307      *
308      * @returns The Token length.
309      */
GetTokenLength(void) const310     uint8_t GetTokenLength(void) const
311     {
312         return (GetHelpData().mHeader.mVersionTypeToken & kTokenLengthMask) >> kTokenLengthOffset;
313     }
314 
315     /**
316      * Returns a pointer to the Token value.
317      *
318      * @returns A pointer to the Token value.
319      */
GetToken(void) const320     const uint8_t *GetToken(void) const { return GetHelpData().mHeader.mToken; }
321 
322     /**
323      * Sets the Token value and length.
324      *
325      * @param[in]  aToken        A pointer to the Token value.
326      * @param[in]  aTokenLength  The Length of @p aToken.
327      *
328      * @retval kErrorNone    Successfully set the token value.
329      * @retval kErrorNoBufs  Insufficient message buffers available to set the token value.
330      */
331     Error SetToken(const uint8_t *aToken, uint8_t aTokenLength);
332 
333     /**
334      * Sets the Token value and length by copying it from another given message.
335      *
336      * @param[in] aMessage       The message to copy the Token from.
337      *
338      * @retval kErrorNone    Successfully set the token value.
339      * @retval kErrorNoBufs  Insufficient message buffers available to set the token value.
340      */
341     Error SetTokenFromMessage(const Message &aMessage);
342 
343     /**
344      * Sets the Token length and randomizes its value.
345      *
346      * @param[in]  aTokenLength  The Length of a Token to set.
347      *
348      * @retval kErrorNone    Successfully set the token value.
349      * @retval kErrorNoBufs  Insufficient message buffers available to set the token value.
350      */
351     Error GenerateRandomToken(uint8_t aTokenLength);
352 
353     /**
354      * Checks if Tokens in two CoAP headers are equal.
355      *
356      * @param[in]  aMessage  A header to compare.
357      *
358      * @retval TRUE   If two Tokens are equal.
359      * @retval FALSE  If Tokens differ in length or value.
360      */
361     bool IsTokenEqual(const Message &aMessage) const;
362 
363     /**
364      * Appends a CoAP option.
365      *
366      * @param[in] aNumber   The CoAP Option number.
367      * @param[in] aLength   The CoAP Option length.
368      * @param[in] aValue    A pointer to the CoAP Option value (@p aLength bytes are used as Option value).
369      *
370      * @retval kErrorNone         Successfully appended the option.
371      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
372      * @retval kErrorNoBufs       The option length exceeds the buffer size.
373      */
374     Error AppendOption(uint16_t aNumber, uint16_t aLength, const void *aValue);
375 
376     /**
377      * Appends a CoAP option reading Option value from another or potentially the same message.
378      *
379      * @param[in] aNumber   The CoAP Option number.
380      * @param[in] aLength   The CoAP Option length.
381      * @param[in] aMessage  The message to read the CoAP Option value from (it can be the same as the current message).
382      * @param[in] aOffset   The offset in @p aMessage to start reading the CoAP Option value from (@p aLength bytes are
383      *                      used as Option value).
384      *
385      * @retval kErrorNone         Successfully appended the option.
386      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
387      * @retval kErrorNoBufs       The option length exceeds the buffer size.
388      * @retval kErrorParse        Not enough bytes in @p aMessage to read @p aLength bytes from @p aOffset.
389      */
390     Error AppendOptionFromMessage(uint16_t aNumber, uint16_t aLength, const Message &aMessage, uint16_t aOffset);
391 
392     /**
393      * Appends an unsigned integer CoAP option as specified in RFC-7252 section-3.2
394      *
395      * @param[in]  aNumber  The CoAP Option number.
396      * @param[in]  aValue   The CoAP Option unsigned integer value.
397      *
398      * @retval kErrorNone         Successfully appended the option.
399      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
400      * @retval kErrorNoBufs       The option length exceeds the buffer size.
401      */
402     Error AppendUintOption(uint16_t aNumber, uint32_t aValue);
403 
404     /**
405      * Appends a string CoAP option.
406      *
407      * @param[in]  aNumber  The CoAP Option number.
408      * @param[in]  aValue   The CoAP Option string value.
409      *
410      * @retval kErrorNone         Successfully appended the option.
411      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
412      * @retval kErrorNoBufs       The option length exceeds the buffer size.
413      */
414     Error AppendStringOption(uint16_t aNumber, const char *aValue);
415 
416     /**
417      * Appends an Observe option.
418      *
419      * @param[in]  aObserve  Observe field value.
420      *
421      * @retval kErrorNone         Successfully appended the option.
422      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
423      * @retval kErrorNoBufs       The option length exceeds the buffer size.
424      */
AppendObserveOption(uint32_t aObserve)425     Error AppendObserveOption(uint32_t aObserve) { return AppendUintOption(kOptionObserve, aObserve & kObserveMask); }
426 
427     /**
428      * Appends a Uri-Path option.
429      *
430      * @param[in]  aUriPath           A pointer to a null-terminated string.
431      *
432      * @retval kErrorNone         Successfully appended the option.
433      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
434      * @retval kErrorNoBufs       The option length exceeds the buffer size.
435      */
436     Error AppendUriPathOptions(const char *aUriPath);
437 
438     /**
439      * Reads the Uri-Path options and constructs the URI path in the buffer referenced by @p `aUriPath`.
440      *
441      * @param[in] aUriPath  A reference to the buffer for storing URI path.
442      *                      NOTE: The buffer size must be `kMaxReceivedUriPath + 1`.
443      *
444      * @retval  kErrorNone   Successfully read the Uri-Path options.
445      * @retval  kErrorParse  CoAP Option header not well-formed.
446      */
447     Error ReadUriPathOptions(char (&aUriPath)[kMaxReceivedUriPath + 1]) const;
448 
449     /**
450      * Appends a Uri-Query option.
451      *
452      * @param[in]  aUriQuery          A pointer to a null-terminated string.
453      *
454      * @retval kErrorNone         Successfully appended the option.
455      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
456      * @retval kErrorNoBufs       The option length exceeds the buffer size.
457      */
458     Error AppendUriQueryOptions(const char *aUriQuery);
459 
460     /**
461      * Appends a Block option
462      *
463      * @param[in]  aType              Type of block option, 1 or 2.
464      * @param[in]  aNum               Current block number.
465      * @param[in]  aMore              Boolean to indicate more blocks are to be sent.
466      * @param[in]  aSize              Maximum block size.
467      *
468      * @retval kErrorNone         Successfully appended the option.
469      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
470      * @retval kErrorNoBufs       The option length exceeds the buffer size.
471      */
472     Error AppendBlockOption(BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSzx aSize);
473 
474     /**
475      * Appends a Proxy-Uri option.
476      *
477      * @param[in]  aProxyUri          A pointer to a null-terminated string.
478      *
479      * @retval kErrorNone         Successfully appended the option.
480      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
481      * @retval kErrorNoBufs       The option length exceeds the buffer size.
482      */
AppendProxyUriOption(const char * aProxyUri)483     Error AppendProxyUriOption(const char *aProxyUri) { return AppendStringOption(kOptionProxyUri, aProxyUri); }
484 
485     /**
486      * Appends a Content-Format option.
487      *
488      * @param[in]  aContentFormat  The Content Format value.
489      *
490      * @retval kErrorNone         Successfully appended the option.
491      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
492      * @retval kErrorNoBufs       The option length exceeds the buffer size.
493      */
AppendContentFormatOption(otCoapOptionContentFormat aContentFormat)494     Error AppendContentFormatOption(otCoapOptionContentFormat aContentFormat)
495     {
496         return AppendUintOption(kOptionContentFormat, static_cast<uint32_t>(aContentFormat));
497     }
498 
499     /**
500      * Appends a Max-Age option.
501      *
502      * @param[in]  aMaxAge  The Max-Age value.
503      *
504      * @retval kErrorNone         Successfully appended the option.
505      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
506      * @retval kErrorNoBufs       The option length exceeds the buffer size.
507      */
AppendMaxAgeOption(uint32_t aMaxAge)508     Error AppendMaxAgeOption(uint32_t aMaxAge) { return AppendUintOption(kOptionMaxAge, aMaxAge); }
509 
510     /**
511      * Appends a single Uri-Query option.
512      *
513      * @param[in]  aUriQuery  A pointer to null-terminated string, which should contain a single key=value pair.
514      *
515      * @retval kErrorNone         Successfully appended the option.
516      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
517      * @retval kErrorNoBufs       The option length exceeds the buffer size.
518      */
AppendUriQueryOption(const char * aUriQuery)519     Error AppendUriQueryOption(const char *aUriQuery) { return AppendStringOption(kOptionUriQuery, aUriQuery); }
520 
521 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
522     /**
523      * Reads the information contained in a Block1 or Block2 option and set it in
524      * the HelpData of the message.
525      *
526      * @param[in]   aBlockType  Block1 or Block2 option value.
527      *
528      * @retval  kErrorNone          The option has been found and is valid.
529      * @retval  kErrorNotFound      The option has not been found.
530      * @retval  kErrorInvalidArgs   The option is invalid.
531      */
532     Error ReadBlockOptionValues(uint16_t aBlockType);
533 
534     /**
535      * Returns the current header length of a message.
536      *
537      * @returns The length of the message header.
538      */
GetHeaderLength(void) const539     uint16_t GetHeaderLength(void) const { return GetHelpData().mHeaderLength; }
540 
541     /**
542      * Returns the block number of a CoAP block-wise transfer message.
543      *
544      * @returns The block number.
545      */
GetBlockWiseBlockNumber(void) const546     uint32_t GetBlockWiseBlockNumber(void) const { return GetHelpData().mBlockWiseData.mBlockNumber; }
547 
548     /**
549      * Checks if the More Blocks flag is set.
550      *
551      * @retval TRUE   More Blocks flag is set.
552      * @retval FALSE  More Blocks flag is not set.
553      */
IsMoreBlocksFlagSet(void) const554     bool IsMoreBlocksFlagSet(void) const { return GetHelpData().mBlockWiseData.mMoreBlocks; }
555 
556     /**
557      * Returns the block size of a CoAP block-wise transfer message.
558      *
559      * @returns The block size.
560      */
GetBlockWiseBlockSize(void) const561     otCoapBlockSzx GetBlockWiseBlockSize(void) const { return GetHelpData().mBlockWiseData.mBlockSize; }
562 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
563 
564     /**
565      * Reads and reassembles the URI path string and fills it into @p aUriPath.
566      *
567      * @retval  kErrorNone      URI path string has been reassembled.
568      * @retval  kErrorNoBufs    URI path string is too long.
569      */
570     Error GetUriPath(char *aUriPath) const;
571 
572     /**
573      * Adds Payload Marker indicating beginning of the payload to the CoAP header.
574      *
575      * It also set offset to the start of payload.
576      *
577      * @retval kErrorNone    Payload Marker successfully added.
578      * @retval kErrorNoBufs  Message Payload Marker exceeds the buffer size.
579      */
580     Error SetPayloadMarker(void);
581 
582     /**
583      * Returns the offset of the first CoAP option.
584      *
585      * @returns The offset of the first CoAP option.
586      */
GetOptionStart(void) const587     uint16_t GetOptionStart(void) const { return kMinHeaderLength + GetTokenLength(); }
588 
589     /**
590      * Parses CoAP header and moves offset end of CoAP header.
591      *
592      * @retval  kErrorNone   Successfully parsed CoAP header from the message.
593      * @retval  kErrorParse  Failed to parse the CoAP header.
594      */
595     Error ParseHeader(void);
596 
597     /**
598      * Sets a default response header based on request header.
599      *
600      * @param[in]  aRequest  The request message.
601      *
602      * @retval kErrorNone    Successfully set the default response header.
603      * @retval kErrorNoBufs  Insufficient message buffers available to set the default response header.
604      */
605     Error SetDefaultResponseHeader(const Message &aRequest);
606 
607 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
608 
609     /**
610      * Sets the block number value in the message HelpData.
611      *
612      * @param[in]   aBlockNumber    Block number value to set.
613      */
SetBlockWiseBlockNumber(uint32_t aBlockNumber)614     void SetBlockWiseBlockNumber(uint32_t aBlockNumber) { GetHelpData().mBlockWiseData.mBlockNumber = aBlockNumber; }
615 
616     /**
617      * Sets the More Blocks flag in the message HelpData.
618      *
619      * @param[in]   aMoreBlocks    TRUE or FALSE.
620      */
SetMoreBlocksFlag(bool aMoreBlocks)621     void SetMoreBlocksFlag(bool aMoreBlocks) { GetHelpData().mBlockWiseData.mMoreBlocks = aMoreBlocks; }
622 
623     /**
624      * Sets the block size value in the message HelpData.
625      *
626      * @param[in]   aBlockSize    Block size value to set.
627      */
SetBlockWiseBlockSize(otCoapBlockSzx aBlockSize)628     void SetBlockWiseBlockSize(otCoapBlockSzx aBlockSize) { GetHelpData().mBlockWiseData.mBlockSize = aBlockSize; }
629 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
630 
631     /**
632      * Checks if a header is an empty message header.
633      *
634      * @retval TRUE   Message is an empty message header.
635      * @retval FALSE  Message is not an empty message header.
636      */
IsEmpty(void) const637     bool IsEmpty(void) const { return (GetCode() == kCodeEmpty); }
638 
639     /**
640      * Checks if a header is a request header.
641      *
642      * @retval TRUE   Message is a request header.
643      * @retval FALSE  Message is not a request header.
644      */
IsRequest(void) const645     bool IsRequest(void) const { return (GetCode() >= kCodeGet) && (GetCode() <= kCodeDelete); }
646 
647     /**
648      * Indicates whether or not the CoAP code in header is "Get" request.
649      *
650      * @retval TRUE   Message is a Get request.
651      * @retval FALSE  Message is not a Get request.
652      */
IsGetRequest(void) const653     bool IsGetRequest(void) const { return GetCode() == kCodeGet; }
654 
655     /**
656      * Indicates whether or not the CoAP code in header is "Post" request.
657      *
658      * @retval TRUE   Message is a Post request.
659      * @retval FALSE  Message is not a Post request.
660      */
IsPostRequest(void) const661     bool IsPostRequest(void) const { return GetCode() == kCodePost; }
662 
663     /**
664      * Indicates whether or not the CoAP code in header is "Put" request.
665      *
666      * @retval TRUE   Message is a Put request.
667      * @retval FALSE  Message is not a Put request.
668      */
IsPutRequest(void) const669     bool IsPutRequest(void) const { return GetCode() == kCodePut; }
670 
671     /**
672      * Indicates whether or not the CoAP code in header is "Delete" request.
673      *
674      * @retval TRUE   Message is a Delete request.
675      * @retval FALSE  Message is not a Delete request.
676      */
IsDeleteRequest(void) const677     bool IsDeleteRequest(void) const { return GetCode() == kCodeDelete; }
678 
679     /**
680      * Checks if a header is a response header.
681      *
682      * @retval TRUE   Message is a response header.
683      * @retval FALSE  Message is not a response header.
684      */
IsResponse(void) const685     bool IsResponse(void) const { return GetCode() >= OT_COAP_CODE_RESPONSE_MIN; }
686 
687     /**
688      * Checks if a header is a CON message header.
689      *
690      * @retval TRUE   Message is a CON message header.
691      * @retval FALSE  Message is not is a CON message header.
692      */
IsConfirmable(void) const693     bool IsConfirmable(void) const { return (GetType() == kTypeConfirmable); }
694 
695     /**
696      * Checks if a header is a NON message header.
697      *
698      * @retval TRUE   Message is a NON message header.
699      * @retval FALSE  Message is not is a NON message header.
700      */
IsNonConfirmable(void) const701     bool IsNonConfirmable(void) const { return (GetType() == kTypeNonConfirmable); }
702 
703     /**
704      * Checks if a header is a ACK message header.
705      *
706      * @retval TRUE   Message is a ACK message header.
707      * @retval FALSE  Message is not is a ACK message header.
708      */
IsAck(void) const709     bool IsAck(void) const { return (GetType() == kTypeAck); }
710 
711     /**
712      * Checks if a header is a RST message header.
713      *
714      * @retval TRUE   Message is a RST message header.
715      * @retval FALSE  Message is not is a RST message header.
716      */
IsReset(void) const717     bool IsReset(void) const { return (GetType() == kTypeReset); }
718 
719     /**
720      * Indicates whether or not the header is a confirmable Post request (i.e, `kTypeConfirmable` with
721      *  `kCodePost`).
722      *
723      * @retval TRUE   Message is a confirmable Post request.
724      * @retval FALSE  Message is not a confirmable Post request.
725      */
726     bool IsConfirmablePostRequest(void) const;
727 
728     /**
729      * Indicates whether or not the header is a non-confirmable Post request (i.e, `kTypeNonConfirmable` with
730      *  `kCodePost`).
731      *
732      * @retval TRUE   Message is a non-confirmable Post request.
733      * @retval FALSE  Message is not a non-confirmable Post request.
734      */
735     bool IsNonConfirmablePostRequest(void) const;
736 
737     /**
738      * Creates a copy of this CoAP message.
739      *
740      * It allocates the new message from the same message pool as the original one and copies @p aLength octets
741      * of the payload. The `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the
742      * cloned message are also copied from the original one.
743      *
744      * @param[in] aLength  Number of payload bytes to copy.
745      *
746      * @returns A pointer to the message or `nullptr` if insufficient message buffers are available.
747      */
748     Message *Clone(uint16_t aLength) const;
749 
750     /**
751      * Creates a copy of the message.
752      *
753      * It allocates the new message from the same message pool as the original one and copies the entire payload. The
754      * `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the cloned message are also
755      * copied from the original one.
756      *
757      * @returns A pointer to the message or `nullptr` if insufficient message buffers are available.
758      */
Clone(void) const759     Message *Clone(void) const { return Clone(GetLength()); }
760 
761     /**
762      * Returns the minimal reserved bytes required for CoAP message.
763      */
GetHelpDataReserved(void)764     static uint16_t GetHelpDataReserved(void) { return sizeof(HelpData) + kHelpDataAlignment; }
765 
766     /**
767      * Returns a pointer to the next message after this as a `Coap::Message`.
768      *
769      * Should be used when the message is in a `Coap::MessageQueue` (i.e., a queue containing only CoAP
770      * messages).
771      *
772      * @returns A pointer to the next message in the queue or `nullptr` if at the end of the queue.
773      */
GetNextCoapMessage(void)774     Message *GetNextCoapMessage(void) { return static_cast<Message *>(GetNext()); }
775 
776     /**
777      * Returns a pointer to the next message after this as a `Coap::Message`.
778      *
779      * Should be used when the message is in a `Coap::MessageQueue` (i.e., a queue containing only CoAP
780      * messages).
781      *
782      * @returns A pointer to the next message in the queue or `nullptr` if at the end of the queue.
783      */
GetNextCoapMessage(void) const784     const Message *GetNextCoapMessage(void) const { return static_cast<const Message *>(GetNext()); }
785 
786 private:
787     /*
788      * Header field first byte (RFC 7252).
789      *
790      *    7 6 5 4 3 2 1 0
791      *   +-+-+-+-+-+-+-+-+
792      *   |Ver| T |  TKL  |  (Version, Type and Token Length).
793      *   +-+-+-+-+-+-+-+-+
794      */
795     static constexpr uint8_t kVersionOffset     = 6;
796     static constexpr uint8_t kVersionMask       = 0x3 << kVersionOffset;
797     static constexpr uint8_t kVersion1          = 1;
798     static constexpr uint8_t kTypeOffset        = 4;
799     static constexpr uint8_t kTypeMask          = 0x3 << kTypeOffset;
800     static constexpr uint8_t kTokenLengthOffset = 0;
801     static constexpr uint8_t kTokenLengthMask   = 0xf << kTokenLengthOffset;
802 
803     /*
804      *
805      * Option Format (RFC 7252).
806      *
807      *      7   6   5   4   3   2   1   0
808      *    +---------------+---------------+
809      *    |  Option Delta | Option Length |   1 byte
810      *    +---------------+---------------+
811      *    /         Option Delta          /   0-2 bytes
812      *    \          (extended)           \
813      *    +-------------------------------+
814      *    /         Option Length         /   0-2 bytes
815      *    \          (extended)           \
816      *    +-------------------------------+
817      *    /         Option Value          /   0 or more bytes
818      *    +-------------------------------+
819      */
820 
821     static constexpr uint8_t kOptionDeltaOffset  = 4;
822     static constexpr uint8_t kOptionDeltaMask    = 0xf << kOptionDeltaOffset;
823     static constexpr uint8_t kOptionLengthOffset = 0;
824     static constexpr uint8_t kOptionLengthMask   = 0xf << kOptionLengthOffset;
825 
826     static constexpr uint8_t kMaxOptionHeaderSize = 5;
827 
828     static constexpr uint8_t kOption1ByteExtension = 13; // Indicates a one-byte extension.
829     static constexpr uint8_t kOption2ByteExtension = 14; // Indicates a two-byte extension.
830 
831     static constexpr uint8_t kPayloadMarker = 0xff;
832 
833     static constexpr uint8_t kHelpDataAlignment = sizeof(uint16_t); // Alignment of help data.
834 
835     static constexpr uint16_t kMinHeaderLength = 4;
836     static constexpr uint16_t kMaxHeaderLength = 512;
837 
838     static constexpr uint16_t kOption1ByteExtensionOffset = 13;  // Delta/Length offset as specified (RFC 7252).
839     static constexpr uint16_t kOption2ByteExtensionOffset = 269; // Delta/Length offset as specified (RFC 7252).
840 
841     static constexpr uint8_t kBlockSzxOffset = 0;
842     static constexpr uint8_t kBlockMOffset   = 3;
843     static constexpr uint8_t kBlockNumOffset = 4;
844 
845     static constexpr uint32_t kObserveMask = 0xffffff;
846     static constexpr uint32_t kBlockNumMax = 0xffff;
847 
848 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
849     struct BlockWiseData
850     {
851         uint32_t       mBlockNumber;
852         bool           mMoreBlocks;
853         otCoapBlockSzx mBlockSize;
854     };
855 #endif
856 
857     /**
858      * Represents a CoAP header excluding CoAP options.
859      */
860     OT_TOOL_PACKED_BEGIN
861     struct Header
862     {
863         uint8_t  mVersionTypeToken;       ///< The CoAP Version, Type, and Token Length
864         uint8_t  mCode;                   ///< The CoAP Code
865         uint16_t mMessageId;              ///< The CoAP Message ID
866         uint8_t  mToken[kMaxTokenLength]; ///< The CoAP Token
867     } OT_TOOL_PACKED_END;
868 
869     /**
870      * Represents a HelpData used by this CoAP message.
871      */
872     struct HelpData : public Clearable<HelpData>
873     {
874         Header   mHeader;
875         uint16_t mOptionLast;
876         uint16_t mHeaderOffset; ///< The byte offset for the CoAP Header
877         uint16_t mHeaderLength;
878         bool     mPayloadMarkerSet;
879 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
880         BlockWiseData mBlockWiseData;
881 #endif
882     };
883 
884     class ConstIterator : public ot::Message::ConstIterator
885     {
886     public:
887         using ot::Message::ConstIterator::ConstIterator;
888 
operator *(void)889         const Message &operator*(void) { return static_cast<const Message &>(ot::Message::ConstIterator::operator*()); }
operator ->(void)890         const Message *operator->(void)
891         {
892             return static_cast<const Message *>(ot::Message::ConstIterator::operator->());
893         }
894     };
895 
896     class Iterator : public ot::Message::Iterator
897     {
898     public:
899         using ot::Message::Iterator::Iterator;
900 
operator *(void)901         Message &operator*(void) { return static_cast<Message &>(ot::Message::Iterator::operator*()); }
operator ->(void)902         Message *operator->(void) { return static_cast<Message *>(ot::Message::Iterator::operator->()); }
903     };
904 
905     static_assert(sizeof(HelpData) <= sizeof(Ip6::Header) + sizeof(Ip6::HopByHopHeader) + sizeof(Ip6::MplOption) +
906                                           sizeof(Ip6::Udp::Header),
907                   "HelpData size exceeds the size of the reserved region in the message");
908 
GetHelpData(void) const909     const HelpData &GetHelpData(void) const
910     {
911         static_assert(sizeof(HelpData) + kHelpDataAlignment <= kHeadBufferDataSize,
912                       "Insufficient buffer size for CoAP processing! Increase OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE.");
913 
914         return *static_cast<const HelpData *>(OT_ALIGN(GetFirstData(), kHelpDataAlignment));
915     }
916 
GetHelpData(void)917     HelpData &GetHelpData(void) { return AsNonConst(AsConst(this)->GetHelpData()); }
918 
GetToken(void)919     uint8_t *GetToken(void) { return GetHelpData().mHeader.mToken; }
920 
SetTokenLength(uint8_t aTokenLength)921     void SetTokenLength(uint8_t aTokenLength)
922     {
923         GetHelpData().mHeader.mVersionTypeToken &= ~kTokenLengthMask;
924         GetHelpData().mHeader.mVersionTypeToken |= ((aTokenLength << kTokenLengthOffset) & kTokenLengthMask);
925     }
926 
927     uint8_t WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer);
928 
929     Error AppendOptionHeader(uint16_t aNumber, uint16_t aLength);
930 };
931 
932 /**
933  * Implements a CoAP message queue.
934  */
935 class MessageQueue : public ot::MessageQueue
936 {
937 public:
938     /**
939      * Initializes the message queue.
940      */
941     MessageQueue(void) = default;
942 
943     /**
944      * Returns a pointer to the first message.
945      *
946      * @returns A pointer to the first message.
947      */
GetHead(void)948     Message *GetHead(void) { return static_cast<Message *>(ot::MessageQueue::GetHead()); }
949 
950     /**
951      * Returns a pointer to the first message.
952      *
953      * @returns A pointer to the first message.
954      */
GetHead(void) const955     const Message *GetHead(void) const { return static_cast<const Message *>(ot::MessageQueue::GetHead()); }
956 
957     /**
958      * Adds a message to the end of the queue.
959      *
960      * @param[in]  aMessage  The message to add.
961      */
Enqueue(Message & aMessage)962     void Enqueue(Message &aMessage) { Enqueue(aMessage, kQueuePositionTail); }
963 
964     /**
965      * Adds a message at a given position (head/tail) of the queue.
966      *
967      * @param[in]  aMessage  The message to add.
968      * @param[in]  aPosition The position (head or tail) where to add the message.
969      */
Enqueue(Message & aMessage,QueuePosition aPosition)970     void Enqueue(Message &aMessage, QueuePosition aPosition) { ot::MessageQueue::Enqueue(aMessage, aPosition); }
971 
972     /**
973      * Removes a message from the queue.
974      *
975      * @param[in]  aMessage  The message to remove.
976      */
Dequeue(Message & aMessage)977     void Dequeue(Message &aMessage) { ot::MessageQueue::Dequeue(aMessage); }
978 
979     /**
980      * Removes a message from the queue and frees it.
981      *
982      * @param[in]  aMessage  The message to remove and free.
983      */
DequeueAndFree(Message & aMessage)984     void DequeueAndFree(Message &aMessage) { ot::MessageQueue::DequeueAndFree(aMessage); }
985 
986     // The following methods are intended to support range-based `for`
987     // loop iteration over the queue entries and should not be used
988     // directly. The range-based `for` works correctly even if the
989     // current entry is removed from the queue during iteration.
990 
991     Message::Iterator begin(void);
end(void)992     Message::Iterator end(void) { return Message::Iterator(); }
993 
994     Message::ConstIterator begin(void) const;
end(void) const995     Message::ConstIterator end(void) const { return Message::ConstIterator(); }
996 };
997 
998 /**
999  * Represents a CoAP option.
1000  */
1001 class Option : public otCoapOption
1002 {
1003 public:
1004     /**
1005      * Represents an iterator for CoAP options.
1006      */
1007     class Iterator : public otCoapOptionIterator
1008     {
1009     public:
1010         /**
1011          * Initializes the iterator to iterate over CoAP Options in a CoAP message.
1012          *
1013          * The iterator MUST be initialized before any other methods are used, otherwise its behavior is undefined.
1014          *
1015          * After initialization, the iterator is either updated to point to the first option, or it is marked as done
1016          * (i.e., `IsDone()` returns `true`) when there is no option or if there is a parse error.
1017          *
1018          * @param[in] aMessage  The CoAP message.
1019          *
1020          * @retval kErrorNone   Successfully initialized. Iterator is either at the first option or done.
1021          * @retval kErrorParse  CoAP Option header in @p aMessage is not well-formed.
1022          */
1023         Error Init(const Message &aMessage);
1024 
1025         /**
1026          * Initializes the iterator to iterate over CoAP Options in a CoAP message matching a given Option
1027          * Number value.
1028          *
1029          * The iterator MUST be initialized before any other methods are used, otherwise its behavior is undefined.
1030          *
1031          * After initialization, the iterator is either updated to point to the first option matching the given Option
1032          * Number value, or it is marked as done (i.e., `IsDone()` returns `true`) when there is no matching option or
1033          * if there is a parse error.
1034          *
1035          * @param[in] aMessage  The CoAP message.
1036          * @param[in] aNumber   The CoAP Option Number.
1037          *
1038          * @retval  kErrorNone   Successfully initialized. Iterator is either at the first matching option or done.
1039          * @retval  kErrorParse  CoAP Option header in @p aMessage is not well-formed.
1040          */
Init(const Message & aMessage,uint16_t aNumber)1041         Error Init(const Message &aMessage, uint16_t aNumber) { return InitOrAdvance(&aMessage, aNumber); }
1042 
1043         /**
1044          * Indicates whether or not the iterator is done (i.e., has reached the end of CoAP Option Header).
1045          *
1046          * @retval TRUE   Iterator is done (reached end of Option header).
1047          * @retval FALSE  Iterator is not done and currently pointing to a CoAP Option.
1048          */
IsDone(void) const1049         bool IsDone(void) const { return mOption.mLength == kIteratorDoneLength; }
1050 
1051         /**
1052          * Indicates whether or not there was a earlier parse error (i.e., whether the iterator is valid).
1053          *
1054          * After a parse errors, iterator would also be marked as done.
1055          *
1056          * @retval TRUE   There was an earlier parse error and the iterator is not valid.
1057          * @retval FALSE  There was no earlier parse error and the iterator is valid.
1058          */
HasParseErrored(void) const1059         bool HasParseErrored(void) const { return mNextOptionOffset == kNextOptionOffsetParseError; }
1060 
1061         /**
1062          * Advances the iterator to the next CoAP Option in the header.
1063          *
1064          * The iterator is updated to point to the next option or marked as done when there are no more options.
1065          *
1066          * @retval  kErrorNone   Successfully advanced the iterator.
1067          * @retval  kErrorParse  CoAP Option header is not well-formed.
1068          */
1069         Error Advance(void);
1070 
1071         /**
1072          * Advances the iterator to the next CoAP Option in the header matching a given Option Number value.
1073          *
1074          * The iterator is updated to point to the next matching option or marked as done when there are no more
1075          * matching options.
1076          *
1077          * @param[in] aNumber   The CoAP Option Number.
1078          *
1079          * @retval  kErrorNone   Successfully advanced the iterator.
1080          * @retval  kErrorParse  CoAP Option header is not well-formed.
1081          */
Advance(uint16_t aNumber)1082         Error Advance(uint16_t aNumber) { return InitOrAdvance(nullptr, aNumber); }
1083 
1084         /**
1085          * Gets the CoAP message associated with the iterator.
1086          *
1087          * @returns A reference to the CoAP message.
1088          */
GetMessage(void) const1089         const Message &GetMessage(void) const { return *static_cast<const Message *>(mMessage); }
1090 
1091         /**
1092          * Gets a pointer to the current CoAP Option to which the iterator is currently pointing.
1093          *
1094          * @returns A pointer to the current CoAP Option, or `nullptr` if iterator is done (or there was an earlier
1095          *          parse error).
1096          */
GetOption(void) const1097         const Option *GetOption(void) const { return IsDone() ? nullptr : static_cast<const Option *>(&mOption); }
1098 
1099         /**
1100          * Reads the current Option Value into a given buffer.
1101          *
1102          * @param[out]  aValue   The pointer to a buffer to copy the Option Value. The buffer is assumed to be
1103          *                       sufficiently large (i.e. at least `GetOption()->GetLength()` bytes).
1104          *
1105          * @retval kErrorNone       Successfully read and copied the Option Value into given buffer.
1106          * @retval kErrorNotFound   Iterator is done (not pointing to any option).
1107          */
1108         Error ReadOptionValue(void *aValue) const;
1109 
1110         /**
1111          * Read the current Option Value which is assumed to be an unsigned integer.
1112          *
1113          * @param[out]  aUintValue      A reference to `uint64_t` to output the read Option Value.
1114          *
1115          * @retval kErrorNone       Successfully read the Option value.
1116          * @retval kErrorNoBufs     Value is too long to fit in an `uint64_t`.
1117          * @retval kErrorNotFound   Iterator is done (not pointing to any option).
1118          */
1119         Error ReadOptionValue(uint64_t &aUintValue) const;
1120 
1121         /**
1122          * Gets the offset of beginning of the CoAP message payload (after the CoAP header).
1123          *
1124          * MUST be used after the iterator is done (i.e. iterated through all options).
1125          *
1126          * @returns The offset of beginning of the CoAP message payload
1127          */
GetPayloadMessageOffset(void) const1128         uint16_t GetPayloadMessageOffset(void) const { return mNextOptionOffset; }
1129 
1130         /**
1131          * Gets the offset of beginning of the CoAP Option Value.
1132          *
1133          * MUST be used during the iterator is in progress.
1134          *
1135          * @returns The offset of beginning of the CoAP Option Value
1136          */
GetOptionValueMessageOffset(void) const1137         uint16_t GetOptionValueMessageOffset(void) const { return mNextOptionOffset - mOption.mLength; }
1138 
1139     private:
1140         // `mOption.mLength` value to indicate iterator is done.
1141         static constexpr uint16_t kIteratorDoneLength = 0xffff;
1142 
1143         // Special `mNextOptionOffset` value to indicate a parse error.
1144         static constexpr uint16_t kNextOptionOffsetParseError = 0;
1145 
MarkAsDone(void)1146         void MarkAsDone(void) { mOption.mLength = kIteratorDoneLength; }
MarkAsParseErrored(void)1147         void MarkAsParseErrored(void) { MarkAsDone(), mNextOptionOffset = kNextOptionOffsetParseError; }
1148 
1149         Error Read(uint16_t aLength, void *aBuffer);
1150         Error ReadExtendedOptionField(uint16_t &aValue);
1151         Error InitOrAdvance(const Message *aMessage, uint16_t aNumber);
1152     };
1153 
1154     /**
1155      * Gets the CoAP Option Number.
1156      *
1157      * @returns The CoAP Option Number.
1158      */
GetNumber(void) const1159     uint16_t GetNumber(void) const { return mNumber; }
1160 
1161     /**
1162      * Gets the CoAP Option Length (length of Option Value in bytes).
1163      *
1164      * @returns The CoAP Option Length (in bytes).
1165      */
GetLength(void) const1166     uint16_t GetLength(void) const { return mLength; }
1167 };
1168 
1169 /**
1170  * @}
1171  */
1172 
1173 } // namespace Coap
1174 
1175 DefineCoreType(otCoapOption, Coap::Option);
1176 DefineCoreType(otCoapOptionIterator, Coap::Option::Iterator);
1177 DefineMapEnum(otCoapType, Coap::Type);
1178 DefineMapEnum(otCoapCode, Coap::Code);
1179 
1180 /**
1181  * Casts an `otMessage` pointer to a `Coap::Message` reference.
1182  *
1183  * @param[in] aMessage   A pointer to an `otMessage`.
1184  *
1185  * @returns A reference to `Coap::Message` matching @p aMessage.
1186  */
AsCoapMessage(otMessage * aMessage)1187 inline Coap::Message &AsCoapMessage(otMessage *aMessage) { return *static_cast<Coap::Message *>(aMessage); }
1188 
1189 /**
1190  * Casts an `otMessage` pointer to a `Coap::Message` reference.
1191  *
1192  * @param[in] aMessage   A pointer to an `otMessage`.
1193  *
1194  * @returns A reference to `Coap::Message` matching @p aMessage.
1195  */
AsCoapMessagePtr(otMessage * aMessage)1196 inline Coap::Message *AsCoapMessagePtr(otMessage *aMessage) { return static_cast<Coap::Message *>(aMessage); }
1197 
1198 /**
1199  * Casts an `otMessage` pointer to a `Coap::Message` pointer.
1200  *
1201  * @param[in] aMessage   A pointer to an `otMessage`.
1202  *
1203  * @returns A pointer to `Coap::Message` matching @p aMessage.
1204  */
AsCoapMessage(const otMessage * aMessage)1205 inline const Coap::Message &AsCoapMessage(const otMessage *aMessage)
1206 {
1207     return *static_cast<const Coap::Message *>(aMessage);
1208 }
1209 
1210 /**
1211  * Casts an `otMessage` pointer to a `Coap::Message` reference.
1212  *
1213  * @param[in] aMessage   A pointer to an `otMessage`.
1214  *
1215  * @returns A pointer to `Coap::Message` matching @p aMessage.
1216  */
AsCoapMessagePtr(const otMessage * aMessage)1217 inline const Coap::Message *AsCoapMessagePtr(const otMessage *aMessage)
1218 {
1219     return static_cast<const Coap::Message *>(aMessage);
1220 }
1221 
1222 } // namespace ot
1223 
1224 #endif // COAP_HEADER_HPP_
1225