• 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 #ifndef COAP_HPP_
30 #define COAP_HPP_
31 
32 #include "openthread-core-config.h"
33 
34 #include <openthread/coap.h>
35 
36 #include "coap/coap_message.hpp"
37 #include "common/as_core_type.hpp"
38 #include "common/debug.hpp"
39 #include "common/linked_list.hpp"
40 #include "common/locator.hpp"
41 #include "common/message.hpp"
42 #include "common/non_copyable.hpp"
43 #include "common/timer.hpp"
44 #include "net/ip6.hpp"
45 #include "net/netif.hpp"
46 #include "net/udp6.hpp"
47 
48 /**
49  * @file
50  *   This file includes definitions for CoAP client and server functionality.
51  */
52 
53 namespace ot {
54 
55 namespace Coap {
56 
57 /**
58  * @addtogroup core-coap
59  *
60  * @{
61  *
62  */
63 
64 /**
65  * This type represents a function pointer which is called when a CoAP response is received or on the request timeout.
66  *
67  * Please see otCoapResponseHandler for details.
68  *
69  */
70 typedef otCoapResponseHandler ResponseHandler;
71 
72 /**
73  * This type represents a function pointer which is called when a CoAP request associated with a given URI path is
74  * received.
75  *
76  * Please see otCoapRequestHandler for details.
77  *
78  */
79 typedef otCoapRequestHandler RequestHandler;
80 
81 /**
82  * This structure represents the CoAP transmission parameters.
83  *
84  */
85 class TxParameters : public otCoapTxParameters
86 {
87     friend class CoapBase;
88     friend class ResponsesQueue;
89 
90 public:
91     /**
92      * This static method coverts a pointer to `otCoapTxParameters` to `Coap::TxParamters`
93      *
94      * If the pointer is `nullptr`, the default parameters are used instead.
95      *
96      * @param[in] aTxParameters   A pointer to tx parameter.
97      *
98      * @returns A reference to corresponding `TxParamters` if  @p aTxParameters is not `nullptr`, otherwise the default
99      *          tx parameters.
100      *
101      */
From(const otCoapTxParameters * aTxParameters)102     static const TxParameters &From(const otCoapTxParameters *aTxParameters)
103     {
104         return aTxParameters ? *static_cast<const TxParameters *>(aTxParameters) : GetDefault();
105     }
106 
107     /**
108      * This method validates whether the CoAP transmission parameters are valid.
109      *
110      * @returns Whether the parameters are valid.
111      *
112      */
113     bool IsValid(void) const;
114 
115     /**
116      * This static method returns default CoAP tx parameters.
117      *
118      * @returns The default tx parameters.
119      *
120      */
GetDefault(void)121     static const TxParameters &GetDefault(void) { return static_cast<const TxParameters &>(kDefaultTxParameters); }
122 
123 private:
124     static constexpr uint32_t kDefaultAckTimeout                 = 2000; // in msec
125     static constexpr uint8_t  kDefaultAckRandomFactorNumerator   = 3;
126     static constexpr uint8_t  kDefaultAckRandomFactorDenominator = 2;
127     static constexpr uint8_t  kDefaultMaxRetransmit              = 4;
128     static constexpr uint32_t kDefaultMaxLatency                 = 100000; // in msec
129 
130     uint32_t CalculateInitialRetransmissionTimeout(void) const;
131     uint32_t CalculateExchangeLifetime(void) const;
132     uint32_t CalculateMaxTransmitWait(void) const;
133     uint32_t CalculateSpan(uint8_t aMaxRetx) const;
134 
135     static const otCoapTxParameters kDefaultTxParameters;
136 };
137 
138 /**
139  * This class implements CoAP resource handling.
140  *
141  */
142 class Resource : public otCoapResource, public LinkedListEntry<Resource>
143 {
144     friend class CoapBase;
145 
146 public:
147     /**
148      * This constructor initializes the resource.
149      *
150      * @param[in]  aUriPath  A pointer to a null-terminated string for the URI path.
151      * @param[in]  aHandler  A function pointer that is called when receiving a CoAP message for @p aUriPath.
152      * @param[in]  aContext  A pointer to arbitrary context information.
153      */
Resource(const char * aUriPath,RequestHandler aHandler,void * aContext)154     Resource(const char *aUriPath, RequestHandler aHandler, void *aContext)
155     {
156         mUriPath = aUriPath;
157         mHandler = aHandler;
158         mContext = aContext;
159         mNext    = nullptr;
160     }
161 
162     /**
163      * This method returns a pointer to the URI path.
164      *
165      * @returns A pointer to the URI path.
166      *
167      */
GetUriPath(void) const168     const char *GetUriPath(void) const { return mUriPath; }
169 
170 protected:
HandleRequest(Message & aMessage,const Ip6::MessageInfo & aMessageInfo) const171     void HandleRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
172     {
173         mHandler(mContext, &aMessage, &aMessageInfo);
174     }
175 };
176 
177 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
178 /**
179  * This class implements CoAP block-wise resource handling.
180  *
181  */
182 class ResourceBlockWise : public otCoapBlockwiseResource
183 {
184     friend class CoapBase;
185 
186 public:
187     /**
188      * This constructor initializes the resource.
189      *
190      * @param[in]  aUriPath         A pointer to a NULL-terminated string for the Uri-Path.
191      * @param[in]  aHandler         A function pointer that is called when receiving a CoAP message for @p aUriPath.
192      * @param[in]  aContext         A pointer to arbitrary context information.
193      * @param[in]  aReceiveHook     A function pointer that is called when receiving a CoAP block message for @p
194      *                              aUriPath.
195      * @param[in]  aTransmitHook    A function pointer that is called when transmitting a CoAP block message from @p
196      *                              aUriPath.
197      */
ResourceBlockWise(const char * aUriPath,otCoapRequestHandler aHandler,void * aContext,otCoapBlockwiseReceiveHook aReceiveHook,otCoapBlockwiseTransmitHook aTransmitHook)198     ResourceBlockWise(const char *                aUriPath,
199                       otCoapRequestHandler        aHandler,
200                       void *                      aContext,
201                       otCoapBlockwiseReceiveHook  aReceiveHook,
202                       otCoapBlockwiseTransmitHook aTransmitHook)
203     {
204         mUriPath      = aUriPath;
205         mHandler      = aHandler;
206         mContext      = aContext;
207         mReceiveHook  = aReceiveHook;
208         mTransmitHook = aTransmitHook;
209         mNext         = nullptr;
210     }
211 
HandleBlockReceive(const uint8_t * aBlock,uint32_t aPosition,uint16_t aBlockLength,bool aMore,uint32_t aTotalLength) const212     Error HandleBlockReceive(const uint8_t *aBlock,
213                              uint32_t       aPosition,
214                              uint16_t       aBlockLength,
215                              bool           aMore,
216                              uint32_t       aTotalLength) const
217     {
218         return mReceiveHook(otCoapBlockwiseResource::mContext, aBlock, aPosition, aBlockLength, aMore, aTotalLength);
219     }
220 
HandleBlockTransmit(uint8_t * aBlock,uint32_t aPosition,uint16_t * aBlockLength,bool * aMore) const221     Error HandleBlockTransmit(uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore) const
222     {
223         return mTransmitHook(otCoapBlockwiseResource::mContext, aBlock, aPosition, aBlockLength, aMore);
224     }
225 
226     /**
227      * This method gets the next entry in the linked list.
228      *
229      * @returns A pointer to the next entry in the linked list or `nullptr` if at the end of the list.
230      *
231      */
GetNext(void) const232     const ResourceBlockWise *GetNext(void) const
233     {
234         return static_cast<const ResourceBlockWise *>(static_cast<const ResourceBlockWise *>(this)->mNext);
235     }
236 
237     /**
238      * This method gets the next entry in the linked list.
239      *
240      * @returns A pointer to the next entry in the linked list or `nullptr` if at the end of the list.
241      *
242      */
GetNext(void)243     ResourceBlockWise *GetNext(void)
244     {
245         return static_cast<ResourceBlockWise *>(static_cast<ResourceBlockWise *>(this)->mNext);
246     }
247 
248     /**
249      * This method sets the next pointer on the entry.
250      *
251      * @param[in] aNext  A pointer to the next entry.
252      *
253      */
SetNext(ResourceBlockWise * aNext)254     void SetNext(ResourceBlockWise *aNext) { static_cast<ResourceBlockWise *>(this)->mNext = aNext; }
255 
256     /**
257      * This method returns a pointer to the URI path.
258      *
259      * @returns A pointer to the URI path.
260      *
261      */
GetUriPath(void) const262     const char *GetUriPath(void) const { return mUriPath; }
263 
264 protected:
HandleRequest(Message & aMessage,const Ip6::MessageInfo & aMessageInfo) const265     void HandleRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
266     {
267         mHandler(mContext, &aMessage, &aMessageInfo);
268     }
269 };
270 #endif
271 
272 /**
273  * This class caches CoAP responses to implement message deduplication.
274  *
275  */
276 class ResponsesQueue
277 {
278 public:
279     /**
280      * Default class constructor.
281      *
282      * @param[in]  aInstance  A reference to the OpenThread instance.
283      *
284      */
285     explicit ResponsesQueue(Instance &aInstance);
286 
287     /**
288      * This method adds a given response to the cache.
289      *
290      * If matching response (the same Message ID, source endpoint address and port) exists in the cache given
291      * response is not added.
292      *
293      * The CoAP response is copied before it is added to the cache.
294      *
295      * @param[in]  aMessage      The CoAP response to add to the cache.
296      * @param[in]  aMessageInfo  The message info corresponding to @p aMessage.
297      * @param[in]  aTxParameters Transmission parameters.
298      *
299      */
300     void EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const TxParameters &aTxParameters);
301 
302     /**
303      * This method removes all responses from the cache.
304      *
305      */
306     void DequeueAllResponses(void);
307 
308     /**
309      * This method gets a copy of CoAP response from the cache that matches a given Message ID and source endpoint.
310      *
311      * @param[in]  aRequest      The CoAP message containing Message ID.
312      * @param[in]  aMessageInfo  The message info containing source endpoint address and port.
313      * @param[out] aResponse     A pointer to return a copy of a cached CoAP response matching given arguments.
314      *
315      * @retval kErrorNone      Matching response found and successfully created a copy.
316      * @retval kErrorNoBufs    Matching response found but there is not sufficient buffer to create a copy.
317      * @retval kErrorNotFound  Matching response not found.
318      *
319      */
320     Error GetMatchedResponseCopy(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo, Message **aResponse);
321 
322     /**
323      * This method gets a reference to the cached CoAP responses queue.
324      *
325      * @returns  A reference to the cached CoAP responses queue.
326      *
327      */
GetResponses(void) const328     const MessageQueue &GetResponses(void) const { return mQueue; }
329 
330 private:
331     static constexpr uint16_t kMaxCachedResponses = OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES;
332 
333     struct ResponseMetadata
334     {
AppendToot::Coap::ResponsesQueue::ResponseMetadata335         Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); }
336         void  ReadFrom(const Message &aMessage);
337 
338         TimeMilli        mDequeueTime;
339         Ip6::MessageInfo mMessageInfo;
340     };
341 
342     const Message *FindMatchedResponse(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo) const;
343     void           DequeueResponse(Message &aMessage);
344     void           UpdateQueue(void);
345 
346     static void HandleTimer(Timer &aTimer);
347     void        HandleTimer(void);
348 
349     MessageQueue      mQueue;
350     TimerMilliContext mTimer;
351 };
352 
353 /**
354  * This class implements the CoAP client and server.
355  *
356  */
357 class CoapBase : public InstanceLocator, private NonCopyable
358 {
359     friend class ResponsesQueue;
360 
361 public:
362 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
363     static constexpr uint16_t kMaxBlockLength = OPENTHREAD_CONFIG_COAP_MAX_BLOCK_LENGTH;
364 #endif
365 
366     /**
367      * This function pointer is called before CoAP server processing a CoAP message.
368      *
369      * @param[in]   aMessage        A reference to the message.
370      @ @param[in]   aMessageInfo    A reference to the message info associated with @p aMessage.
371      * @param[in]   aContext        A pointer to arbitrary context information.
372      *
373      * @retval  kErrorNone      Server should continue processing this message, other return values indicates the
374      *                          server should stop processing this message.
375      * @retval  kErrorNotTmf    The message is not a TMF message.
376      *
377      */
378     typedef Error (*Interceptor)(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext);
379 
380     /**
381      * This method clears requests and responses used by this CoAP agent.
382      *
383      */
384     void ClearRequestsAndResponses(void);
385 
386     /**
387      * This method clears requests with specified source address used by this CoAP agent.
388      *
389      * @param[in]  aAddress A reference to the specified address.
390      *
391      */
392     void ClearRequests(const Ip6::Address &aAddress);
393 
394 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
395 
396     /**
397      * This method adds a block-wise resource to the CoAP server.
398      *
399      * @param[in]  aResource  A reference to the resource.
400      *
401      */
402     void AddBlockWiseResource(ResourceBlockWise &aResource);
403 
404     /**
405      * This method removes a block-wise resource from the CoAP server.
406      *
407      * @param[in]  aResource  A reference to the resource.
408      *
409      */
410     void RemoveBlockWiseResource(ResourceBlockWise &aResource);
411 #endif
412 
413     /**
414      * This method adds a resource to the CoAP server.
415      *
416      * @param[in]  aResource  A reference to the resource.
417      *
418      */
419     void AddResource(Resource &aResource);
420 
421     /**
422      * This method removes a resource from the CoAP server.
423      *
424      * @param[in]  aResource  A reference to the resource.
425      *
426      */
427     void RemoveResource(Resource &aResource);
428 
429     /* This method sets the default handler for unhandled CoAP requests.
430      *
431      * @param[in]  aHandler   A function pointer that shall be called when an unhandled request arrives.
432      * @param[in]  aContext   A pointer to arbitrary context information. May be `nullptr` if not used.
433      *
434      */
435     void SetDefaultHandler(RequestHandler aHandler, void *aContext);
436 
437     /**
438      * This method allocates a new message with a CoAP header.
439      *
440      * @param[in]  aSettings  The message settings.
441      *
442      * @returns A pointer to the message or `nullptr` if failed to allocate message.
443      *
444      */
445     Message *NewMessage(const Message::Settings &aSettings = Message::Settings::GetDefault());
446 
447     /**
448      * This method allocates a new message with a CoAP header that has Network Control priority level.
449      *
450      * @returns A pointer to the message or `nullptr` if failed to allocate message.
451      *
452      */
NewPriorityMessage(void)453     Message *NewPriorityMessage(void)
454     {
455         return NewMessage(Message::Settings(Message::kWithLinkSecurity, Message::kPriorityNet));
456     }
457 
458     /**
459      * This method allocates and initializes a new CoAP Confirmable Post message with Network Control priority level.
460      *
461      * The CoAP header is initialized as `kTypeConfirmable` and `kCodePost` with a given URI path and a randomly
462      * generated token (of default length). This method also sets the payload marker (`SetPayloadMarker()` on message.
463      * Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and
464      * remove the payload marker when there is no payload.
465      *
466      * @param[in] aUriPath   The URI path string.
467      *
468      * @returns A pointer to the message or `nullptr` if failed to allocate message.
469      *
470      */
471     Message *NewPriorityConfirmablePostMessage(const char *aUriPath);
472 
473     /**
474      * This method allocates and initializes a new CoAP Confirmable Post message with normal priority level.
475      *
476      * The CoAP header is initialized as `kTypeConfirmable` and `kCodePost` with a given URI path and a randomly
477      * generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`).
478      * Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and
479      * remove the payload marker when there is no payload.
480      *
481      * @param[in] aUriPath   The URI path string.
482      *
483      * @returns A pointer to the message or `nullptr` if failed to allocate message.
484      *
485      */
486     Message *NewConfirmablePostMessage(const char *aUriPath);
487 
488     /**
489      * This method allocates and initializes a new CoAP Non-confirmable Post message with Network Control priority
490      * level.
491      *
492      * The CoAP header is initialized as `kTypeNonConfirmable` and `kCodePost` with a given URI path and a randomly
493      * generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`).
494      * Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and
495      * remove the payload marker when there is no payload.
496      *
497      * @param[in] aUriPath   The URI path string.
498      *
499      * @returns A pointer to the message or `nullptr` if failed to allocate message.
500      *
501      */
502     Message *NewPriorityNonConfirmablePostMessage(const char *aUriPath);
503 
504     /**
505      * This method allocates and initializes a new CoAP Non-confirmable Post message with normal priority level.
506      *
507      * The CoAP header is initialized as `kTypeNonConfirmable` and `kCodePost` with a given URI path and a randomly
508      * generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`).
509      * Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and
510      * remove the payload marker when there is no payload.
511      *
512      * @param[in] aUriPath   The URI path string.
513      *
514      * @returns A pointer to the message or `nullptr` if failed to allocate message.
515      *
516      */
517     Message *NewNonConfirmablePostMessage(const char *aUriPath);
518 
519     /**
520      * This method allocates and initializes a new CoAP response message with Network Control priority level for a
521      * given request message.
522      *
523      * The CoAP header is initialized as `kTypeAck` with `kCodeChanged`. The token and message ID is copied from
524      * @p aRequest. This method also sets the payload marker (calling `SetPayloadMarker()`). Even if message has
525      * no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and remove the payload
526      * marker when there is no payload.
527      *
528      * @returns A pointer to the message or `nullptr` if failed to allocate message.
529      *
530      */
531     Message *NewPriorityResponseMessage(const Message &aRequest);
532 
533     /**
534      * This method allocates and initializes a new CoAP response message with regular priority level for a given
535      * request message.
536      *
537      * The CoAP header is initialized as `kTypeAck` with `kCodeChanged`. The token and message ID is copied from
538      * @p aRequest. This method also sets the payload marker (calling `SetPayloadMarker()`). Even if message has
539      * no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and remove the payload
540      * marker when there is no payload.
541      *
542      * @returns A pointer to the message or `nullptr` if failed to allocate message.
543      *
544      */
545     Message *NewResponseMessage(const Message &aRequest);
546 
547 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
548     /**
549      * This method sends a CoAP message block-wise with custom transmission parameters.
550      *
551      * If a response for a request is expected, respective function and context information should be provided.
552      * If no response is expected, these arguments should be NULL pointers.
553      * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
554      *
555      * @param[in]  aMessage      A reference to the message to send.
556      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
557      * @param[in]  aTxParameters A reference to transmission parameters for this message.
558      * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
559      * @param[in]  aContext      A pointer to arbitrary context information.
560      * @param[in]  aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
561      * @param[in]  aReceiveHook  A pointer to a hook function for incoming block-wise transfer.
562      *
563      * @retval kErrorNone     Successfully sent CoAP message.
564      * @retval kErrorNoBufs   Failed to allocate retransmission data.
565      *
566      */
567     Error SendMessage(Message &                   aMessage,
568                       const Ip6::MessageInfo &    aMessageInfo,
569                       const TxParameters &        aTxParameters,
570                       otCoapResponseHandler       aHandler      = nullptr,
571                       void *                      aContext      = nullptr,
572                       otCoapBlockwiseTransmitHook aTransmitHook = nullptr,
573                       otCoapBlockwiseReceiveHook  aReceiveHook  = nullptr);
574 #else  // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
575 
576     /**
577      * This method sends a CoAP message with custom transmission parameters.
578      *
579      * If a response for a request is expected, respective function and context information should be provided.
580      * If no response is expected, these arguments should be `nullptr` pointers.
581      * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
582      *
583      * @param[in]  aMessage      A reference to the message to send.
584      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
585      * @param[in]  aTxParameters A reference to transmission parameters for this message.
586      * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
587      * @param[in]  aContext      A pointer to arbitrary context information.
588      *
589      * @retval kErrorNone    Successfully sent CoAP message.
590      * @retval kErrorNoBufs  Insufficient buffers available to send the CoAP message.
591      *
592      */
593     Error SendMessage(Message &               aMessage,
594                       const Ip6::MessageInfo &aMessageInfo,
595                       const TxParameters &    aTxParameters,
596                       ResponseHandler         aHandler = nullptr,
597                       void *                  aContext = nullptr);
598 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
599 
600     /**
601      * This method sends a CoAP message with default transmission parameters.
602      *
603      * If a response for a request is expected, respective function and context information should be provided.
604      * If no response is expected, these arguments should be `nullptr` pointers.
605      * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
606      *
607      * @param[in]  aMessage      A reference to the message to send.
608      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
609      * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
610      * @param[in]  aContext      A pointer to arbitrary context information.
611      *
612      * @retval kErrorNone    Successfully sent CoAP message.
613      * @retval kErrorNoBufs  Insufficient buffers available to send the CoAP response.
614      *
615      */
616     Error SendMessage(Message &               aMessage,
617                       const Ip6::MessageInfo &aMessageInfo,
618                       ResponseHandler         aHandler = nullptr,
619                       void *                  aContext = nullptr);
620 
621     /**
622      * This method sends a CoAP reset message.
623      *
624      * @param[in]  aRequest        A reference to the CoAP Message that was used in CoAP request.
625      * @param[in]  aMessageInfo    The message info corresponding to the CoAP request.
626      *
627      * @retval kErrorNone          Successfully enqueued the CoAP response message.
628      * @retval kErrorNoBufs        Insufficient buffers available to send the CoAP response.
629      * @retval kErrorInvalidArgs   The @p aRequest is not of confirmable type.
630      *
631      */
632     Error SendReset(Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
633 
634     /**
635      * This method sends header-only CoAP response message.
636      *
637      * @param[in]  aCode           The CoAP code of this response.
638      * @param[in]  aRequest        A reference to the CoAP Message that was used in CoAP request.
639      * @param[in]  aMessageInfo    The message info corresponding to the CoAP request.
640      *
641      * @retval kErrorNone          Successfully enqueued the CoAP response message.
642      * @retval kErrorNoBufs        Insufficient buffers available to send the CoAP response.
643      * @retval kErrorInvalidArgs   The @p aRequest header is not of confirmable type.
644      *
645      */
646     Error SendHeaderResponse(Message::Code aCode, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
647 
648     /**
649      * This method sends a CoAP ACK empty message which is used in Separate Response for confirmable requests.
650      *
651      * @param[in]  aRequest        A reference to the CoAP Message that was used in CoAP request.
652      * @param[in]  aMessageInfo    The message info corresponding to the CoAP request.
653      *
654      * @retval kErrorNone          Successfully enqueued the CoAP response message.
655      * @retval kErrorNoBufs        Insufficient buffers available to send the CoAP response.
656      * @retval kErrorInvalidArgs   The @p aRequest header is not of confirmable type.
657      *
658      */
659     Error SendAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
660 
661     /**
662      * This method sends a CoAP ACK message on which a dummy CoAP response is piggybacked.
663      *
664      * @param[in]  aRequest        A reference to the CoAP Message that was used in CoAP request.
665      * @param[in]  aMessageInfo    The message info corresponding to the CoAP request.
666      * @param[in]  aCode           The CoAP code of the dummy CoAP response.
667      *
668      * @retval kErrorNone          Successfully enqueued the CoAP response message.
669      * @retval kErrorNoBufs        Insufficient buffers available to send the CoAP response.
670      * @retval kErrorInvalidArgs   The @p aRequest header is not of confirmable type.
671      *
672      */
673     Error SendEmptyAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo, Code aCode = kCodeChanged);
674 
675     /**
676      * This method sends a header-only CoAP message to indicate no resource matched for the request.
677      *
678      * @param[in]  aRequest        A reference to the CoAP Message that was used in CoAP request.
679      * @param[in]  aMessageInfo    The message info corresponding to the CoAP request.
680      *
681      * @retval kErrorNone          Successfully enqueued the CoAP response message.
682      * @retval kErrorNoBufs        Insufficient buffers available to send the CoAP response.
683      *
684      */
685     Error SendNotFound(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
686 
687 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
688     /**
689      * This method sends a header-only CoAP message to indicate not all blocks have been sent or
690      * were sent out of order.
691      *
692      * @param[in]  aRequest        A reference to the CoAP Message that was used in CoAP request.
693      * @param[in]  aMessageInfo    The message info corresponding to the CoAP request.
694      *
695      * @retval kErrorNone          Successfully enqueued the CoAP response message.
696      * @retval kErrorNoBufs        Insufficient buffers available to send the CoAP response.
697      *
698      */
SendRequestEntityIncomplete(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)699     Error SendRequestEntityIncomplete(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
700     {
701         return SendHeaderResponse(kCodeRequestIncomplete, aRequest, aMessageInfo);
702     }
703 #endif
704 
705     /**
706      * This method aborts CoAP transactions associated with given handler and context.
707      *
708      * The associated response handler will be called with kErrorAbort.
709      *
710      * @param[in]  aHandler  A function pointer that should be called when the transaction ends.
711      * @param[in]  aContext  A pointer to arbitrary context information.
712      *
713      * @retval kErrorNone      Successfully aborted CoAP transactions.
714      * @retval kErrorNotFound  CoAP transaction associated with given handler was not found.
715      *
716      */
717     Error AbortTransaction(ResponseHandler aHandler, void *aContext);
718 
719     /**
720      * This method sets interceptor to be called before processing a CoAP packet.
721      *
722      * @param[in]   aInterceptor    A pointer to the interceptor.
723      * @param[in]   aContext        A pointer to arbitrary context information.
724      *
725      */
726     void SetInterceptor(Interceptor aInterceptor, void *aContext);
727 
728     /**
729      * This method returns a reference to the request message list.
730      *
731      * @returns A reference to the request message list.
732      *
733      */
GetRequestMessages(void) const734     const MessageQueue &GetRequestMessages(void) const { return mPendingRequests; }
735 
736     /**
737      * This method returns a reference to the cached response list.
738      *
739      * @returns A reference to the cached response list.
740      *
741      */
GetCachedResponses(void) const742     const MessageQueue &GetCachedResponses(void) const { return mResponsesQueue.GetResponses(); }
743 
744 protected:
745     /**
746      * This function pointer is called to send a CoAP message.
747      *
748      * @param[in]  aCoapBase     A reference to the CoAP agent.
749      * @param[in]  aMessage      A reference to the message to send.
750      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
751      *
752      * @retval kErrorNone    Successfully sent CoAP message.
753      * @retval kErrorNoBufs  Failed to allocate retransmission data.
754      *
755      */
756     typedef Error (*Sender)(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
757 
758     /**
759      * This constructor initializes the object.
760      *
761      * @param[in]  aInstance        A reference to the OpenThread instance.
762      * @param[in]  aSender          A function pointer to send CoAP message, which SHOULD be a static
763      *                              member method of a descendant of this class.
764      *
765      */
766     CoapBase(Instance &aInstance, Sender aSender);
767 
768     /**
769      * This method receives a CoAP message.
770      *
771      * @param[in]  aMessage      A reference to the received message.
772      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
773      *
774      */
775     void Receive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
776 
777 private:
778     struct Metadata
779     {
AppendToot::Coap::CoapBase::Metadata780         Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); }
781         void  ReadFrom(const Message &aMessage);
782         void  UpdateIn(Message &aMessage) const;
783 
784         Ip6::Address    mSourceAddress;            // IPv6 address of the message source.
785         Ip6::Address    mDestinationAddress;       // IPv6 address of the message destination.
786         uint16_t        mDestinationPort;          // UDP port of the message destination.
787         ResponseHandler mResponseHandler;          // A function pointer that is called on response reception.
788         void *          mResponseContext;          // A pointer to arbitrary context information.
789         TimeMilli       mNextTimerShot;            // Time when the timer should shoot for this message.
790         uint32_t        mRetransmissionTimeout;    // Delay that is applied to next retransmission.
791         uint8_t         mRetransmissionsRemaining; // Number of retransmissions remaining.
792 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
793         uint8_t mHopLimit; // The hop limit.
794 #endif
795         bool mAcknowledged : 1;  // Information that request was acknowledged.
796         bool mConfirmable : 1;   // Information that message is confirmable.
797         bool mMulticastLoop : 1; // Information that multicast loop is enabled.
798 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
799         bool mIsHostInterface : 1; // TRUE if packets sent/received via host interface, FALSE otherwise.
800 #endif
801 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
802         bool mObserve : 1; // Information that this request involves Observations.
803 #endif
804 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
805         otCoapBlockwiseReceiveHook  mBlockwiseReceiveHook;  // Function pointer called on Block2 response reception.
806         otCoapBlockwiseTransmitHook mBlockwiseTransmitHook; // Function pointer called on Block1 response reception.
807 #endif
808     };
809 
810     Message *InitMessage(Message *aMessage, Type aType, const char *aUriPath);
811     Message *InitResponse(Message *aMessage, const Message &aResponse);
812 
813     static void HandleRetransmissionTimer(Timer &aTimer);
814     void        HandleRetransmissionTimer(void);
815 
816     void     ClearRequests(const Ip6::Address *aAddress);
817     Message *CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopyLength, const Metadata &aMetadata);
818     void     DequeueMessage(Message &aMessage);
819     Message *FindRelatedRequest(const Message &aResponse, const Ip6::MessageInfo &aMessageInfo, Metadata &aMetadata);
820     void     FinalizeCoapTransaction(Message &               aRequest,
821                                      const Metadata &        aMetadata,
822                                      Message *               aResponse,
823                                      const Ip6::MessageInfo *aMessageInfo,
824                                      Error                   aResult);
825 
826 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
827     void  FreeLastBlockResponse(void);
828     Error CacheLastBlockResponse(Message *aResponse);
829 
830     Error PrepareNextBlockRequest(Message::BlockType aType,
831                                   bool               aMoreBlocks,
832                                   Message &          aRequestOld,
833                                   Message &          aRequest,
834                                   Message &          aMessage);
835     Error ProcessBlock1Request(Message &                aMessage,
836                                const Ip6::MessageInfo & aMessageInfo,
837                                const ResourceBlockWise &aResource,
838                                uint32_t                 aTotalLength);
839     Error ProcessBlock2Request(Message &                aMessage,
840                                const Ip6::MessageInfo & aMessageInfo,
841                                const ResourceBlockWise &aResource);
842 #endif
843     void ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
844     void ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
845 
846 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
847     Error SendNextBlock1Request(Message &               aRequest,
848                                 Message &               aMessage,
849                                 const Ip6::MessageInfo &aMessageInfo,
850                                 const Metadata &        aCoapMetadata);
851     Error SendNextBlock2Request(Message &               aRequest,
852                                 Message &               aMessage,
853                                 const Ip6::MessageInfo &aMessageInfo,
854                                 const Metadata &        aCoapMetadata,
855                                 uint32_t                aTotalLength,
856                                 bool                    aBeginBlock1Transfer);
857 #endif
858     void  SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
859     Error SendEmptyMessage(Type aType, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
860 
861     Error Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
862 
863     MessageQueue      mPendingRequests;
864     uint16_t          mMessageId;
865     TimerMilliContext mRetransmissionTimer;
866 
867     LinkedList<Resource> mResources;
868 
869     void *         mContext;
870     Interceptor    mInterceptor;
871     ResponsesQueue mResponsesQueue;
872 
873     RequestHandler mDefaultHandler;
874     void *         mDefaultHandlerContext;
875 
876     const Sender mSender;
877 
878 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
879     LinkedList<ResourceBlockWise> mBlockWiseResources;
880     Message *                     mLastResponse;
881 #endif
882 };
883 
884 /**
885  * This class implements the CoAP client and server.
886  *
887  */
888 class Coap : public CoapBase
889 {
890 public:
891     /**
892      * This constructor initializes the object.
893      *
894      * @param[in] aInstance      A reference to the OpenThread instance.
895      *
896      */
897     explicit Coap(Instance &aInstance);
898 
899     /**
900      * This method starts the CoAP service.
901      *
902      * @param[in]  aPort             The local UDP port to bind to.
903      * @param[in]  aNetifIdentifier  The network interface identifier to bind.
904      *
905      * @retval kErrorNone    Successfully started the CoAP service.
906      * @retval kErrorFailed  Failed to start CoAP agent.
907      *
908      */
909     Error Start(uint16_t aPort, otNetifIdentifier aNetifIdentifier = OT_NETIF_UNSPECIFIED);
910 
911     /**
912      * This method stops the CoAP service.
913      *
914      * @retval kErrorNone    Successfully stopped the CoAP service.
915      * @retval kErrorFailed  Failed to stop CoAP agent.
916      *
917      */
918     Error Stop(void);
919 
920 protected:
921     Ip6::Udp::Socket mSocket;
922 
923 private:
924     static Error Send(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
925     static void  HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
926     Error        Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
927 };
928 
929 } // namespace Coap
930 
931 DefineCoreType(otCoapTxParameters, Coap::TxParameters);
932 DefineCoreType(otCoapResource, Coap::Resource);
933 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
934 DefineCoreType(otCoapBlockwiseResource, Coap::ResourceBlockWise);
935 #endif
936 
937 } // namespace ot
938 
939 #endif // COAP_HPP_
940