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