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