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