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