xref: /aosp_15_r20/external/openthread/src/core/coap/coap.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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 #include "coap.hpp"
30 
31 #include "common/array.hpp"
32 #include "common/as_core_type.hpp"
33 #include "common/code_utils.hpp"
34 #include "common/debug.hpp"
35 #include "common/locator_getters.hpp"
36 #include "common/log.hpp"
37 #include "common/random.hpp"
38 #include "common/string.hpp"
39 #include "instance/instance.hpp"
40 #include "net/ip6.hpp"
41 #include "net/udp6.hpp"
42 #include "thread/thread_netif.hpp"
43 
44 /**
45  * @file
46  *   This file contains common code base for CoAP client and server.
47  */
48 
49 namespace ot {
50 namespace Coap {
51 
52 RegisterLogModule("Coap");
53 
CoapBase(Instance & aInstance,Sender aSender)54 CoapBase::CoapBase(Instance &aInstance, Sender aSender)
55     : InstanceLocator(aInstance)
56     , mMessageId(Random::NonCrypto::GetUint16())
57     , mRetransmissionTimer(aInstance, Coap::HandleRetransmissionTimer, this)
58     , mResponsesQueue(aInstance)
59     , mResourceHandler(nullptr)
60     , mSender(aSender)
61 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
62     , mLastResponse(nullptr)
63 #endif
64 {
65 }
66 
ClearRequestsAndResponses(void)67 void CoapBase::ClearRequestsAndResponses(void)
68 {
69     ClearRequests(nullptr); // Clear requests matching any address.
70     mResponsesQueue.DequeueAllResponses();
71 }
72 
ClearRequests(const Ip6::Address & aAddress)73 void CoapBase::ClearRequests(const Ip6::Address &aAddress) { ClearRequests(&aAddress); }
74 
ClearRequests(const Ip6::Address * aAddress)75 void CoapBase::ClearRequests(const Ip6::Address *aAddress)
76 {
77     for (Message &message : mPendingRequests)
78     {
79         Metadata metadata;
80 
81         metadata.ReadFrom(message);
82 
83         if ((aAddress == nullptr) || (metadata.mSourceAddress == *aAddress))
84         {
85             FinalizeCoapTransaction(message, metadata, nullptr, nullptr, kErrorAbort);
86         }
87     }
88 }
89 
90 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
AddBlockWiseResource(ResourceBlockWise & aResource)91 void CoapBase::AddBlockWiseResource(ResourceBlockWise &aResource) { IgnoreError(mBlockWiseResources.Add(aResource)); }
92 
RemoveBlockWiseResource(ResourceBlockWise & aResource)93 void CoapBase::RemoveBlockWiseResource(ResourceBlockWise &aResource)
94 {
95     IgnoreError(mBlockWiseResources.Remove(aResource));
96     aResource.SetNext(nullptr);
97 }
98 #endif
99 
AddResource(Resource & aResource)100 void CoapBase::AddResource(Resource &aResource) { IgnoreError(mResources.Add(aResource)); }
101 
RemoveResource(Resource & aResource)102 void CoapBase::RemoveResource(Resource &aResource)
103 {
104     IgnoreError(mResources.Remove(aResource));
105     aResource.SetNext(nullptr);
106 }
107 
NewMessage(const Message::Settings & aSettings)108 Message *CoapBase::NewMessage(const Message::Settings &aSettings)
109 {
110     Message *message = nullptr;
111 
112     VerifyOrExit((message = AsCoapMessagePtr(Get<Ip6::Udp>().NewMessage(0, aSettings))) != nullptr);
113     message->SetOffset(0);
114 
115 exit:
116     return message;
117 }
118 
NewMessage(void)119 Message *CoapBase::NewMessage(void) { return NewMessage(Message::Settings::GetDefault()); }
120 
NewPriorityMessage(void)121 Message *CoapBase::NewPriorityMessage(void)
122 {
123     return NewMessage(Message::Settings(Message::kWithLinkSecurity, Message::kPriorityNet));
124 }
125 
NewPriorityConfirmablePostMessage(Uri aUri)126 Message *CoapBase::NewPriorityConfirmablePostMessage(Uri aUri)
127 {
128     return InitMessage(NewPriorityMessage(), kTypeConfirmable, aUri);
129 }
130 
NewConfirmablePostMessage(Uri aUri)131 Message *CoapBase::NewConfirmablePostMessage(Uri aUri) { return InitMessage(NewMessage(), kTypeConfirmable, aUri); }
132 
NewPriorityNonConfirmablePostMessage(Uri aUri)133 Message *CoapBase::NewPriorityNonConfirmablePostMessage(Uri aUri)
134 {
135     return InitMessage(NewPriorityMessage(), kTypeNonConfirmable, aUri);
136 }
137 
NewNonConfirmablePostMessage(Uri aUri)138 Message *CoapBase::NewNonConfirmablePostMessage(Uri aUri)
139 {
140     return InitMessage(NewMessage(), kTypeNonConfirmable, aUri);
141 }
142 
NewPriorityResponseMessage(const Message & aRequest)143 Message *CoapBase::NewPriorityResponseMessage(const Message &aRequest)
144 {
145     return InitResponse(NewPriorityMessage(), aRequest);
146 }
147 
NewResponseMessage(const Message & aRequest)148 Message *CoapBase::NewResponseMessage(const Message &aRequest) { return InitResponse(NewMessage(), aRequest); }
149 
InitMessage(Message * aMessage,Type aType,Uri aUri)150 Message *CoapBase::InitMessage(Message *aMessage, Type aType, Uri aUri)
151 {
152     Error error = kErrorNone;
153 
154     VerifyOrExit(aMessage != nullptr);
155 
156     SuccessOrExit(error = aMessage->Init(aType, kCodePost, aUri));
157     SuccessOrExit(error = aMessage->SetPayloadMarker());
158 
159 exit:
160     FreeAndNullMessageOnError(aMessage, error);
161     return aMessage;
162 }
163 
InitResponse(Message * aMessage,const Message & aRequest)164 Message *CoapBase::InitResponse(Message *aMessage, const Message &aRequest)
165 {
166     Error error = kErrorNone;
167 
168     VerifyOrExit(aMessage != nullptr);
169 
170     SuccessOrExit(error = aMessage->SetDefaultResponseHeader(aRequest));
171     SuccessOrExit(error = aMessage->SetPayloadMarker());
172 
173 exit:
174     FreeAndNullMessageOnError(aMessage, error);
175     return aMessage;
176 }
177 
Send(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)178 Error CoapBase::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
179 {
180     Error error;
181 
182 #if OPENTHREAD_CONFIG_OTNS_ENABLE
183     Get<Utils::Otns>().EmitCoapSend(AsCoapMessage(&aMessage), aMessageInfo);
184 #endif
185 
186     error = mSender(*this, aMessage, aMessageInfo);
187 
188 #if OPENTHREAD_CONFIG_OTNS_ENABLE
189     if (error != kErrorNone)
190     {
191         Get<Utils::Otns>().EmitCoapSendFailure(error, AsCoapMessage(&aMessage), aMessageInfo);
192     }
193 #endif
194     return error;
195 }
196 
197 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
SendMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const TxParameters & aTxParameters,ResponseHandler aHandler,void * aContext,otCoapBlockwiseTransmitHook aTransmitHook,otCoapBlockwiseReceiveHook aReceiveHook)198 Error CoapBase::SendMessage(Message                    &aMessage,
199                             const Ip6::MessageInfo     &aMessageInfo,
200                             const TxParameters         &aTxParameters,
201                             ResponseHandler             aHandler,
202                             void                       *aContext,
203                             otCoapBlockwiseTransmitHook aTransmitHook,
204                             otCoapBlockwiseReceiveHook  aReceiveHook)
205 #else
206 Error CoapBase::SendMessage(Message                &aMessage,
207                             const Ip6::MessageInfo &aMessageInfo,
208                             const TxParameters     &aTxParameters,
209                             ResponseHandler         aHandler,
210                             void                   *aContext)
211 #endif
212 {
213     Error    error;
214     Message *storedCopy = nullptr;
215     uint16_t copyLength = 0;
216 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
217     uint8_t  buf[kMaxBlockLength] = {0};
218     uint16_t bufLen               = kMaxBlockLength;
219     bool     moreBlocks           = false;
220 #endif
221 
222     switch (aMessage.GetType())
223     {
224     case kTypeAck:
225 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
226         // Check for block-wise transfer
227         if ((aTransmitHook != nullptr) && (aMessage.ReadBlockOptionValues(kOptionBlock2) == kErrorNone) &&
228             (aMessage.GetBlockWiseBlockNumber() == 0))
229         {
230             // Set payload for first block of the transfer
231             VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
232                          error = kErrorNoBufs);
233             SuccessOrExit(error = aTransmitHook(aContext, buf, aMessage.GetBlockWiseBlockNumber() * bufLen, &bufLen,
234                                                 &moreBlocks));
235             SuccessOrExit(error = aMessage.AppendBytes(buf, bufLen));
236 
237             SuccessOrExit(error = CacheLastBlockResponse(&aMessage));
238         }
239 #endif
240 
241         mResponsesQueue.EnqueueResponse(aMessage, aMessageInfo, aTxParameters);
242         break;
243     case kTypeReset:
244         OT_ASSERT(aMessage.GetCode() == kCodeEmpty);
245         break;
246     default:
247 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
248         // Check for block-wise transfer
249         if ((aTransmitHook != nullptr) && (aMessage.ReadBlockOptionValues(kOptionBlock1) == kErrorNone) &&
250             (aMessage.GetBlockWiseBlockNumber() == 0))
251         {
252             // Set payload for first block of the transfer
253             VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
254                          error = kErrorNoBufs);
255             SuccessOrExit(error = aTransmitHook(aContext, buf, aMessage.GetBlockWiseBlockNumber() * bufLen, &bufLen,
256                                                 &moreBlocks));
257             SuccessOrExit(error = aMessage.AppendBytes(buf, bufLen));
258 
259             // Block-Wise messages always have to be confirmable
260             if (aMessage.IsNonConfirmable())
261             {
262                 aMessage.SetType(kTypeConfirmable);
263             }
264         }
265 #endif
266 
267         aMessage.SetMessageId(mMessageId++);
268         break;
269     }
270 
271     aMessage.Finish();
272 
273     if (aMessage.IsConfirmable())
274     {
275         copyLength = aMessage.GetLength();
276     }
277     else if (aMessage.IsNonConfirmable() && (aHandler != nullptr))
278     {
279         // As we do not retransmit non confirmable messages, create a
280         // copy of header only, for token information.
281         copyLength = aMessage.GetOptionStart();
282     }
283 
284     if (copyLength > 0)
285     {
286         Metadata metadata;
287 
288 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
289         // Whether or not to turn on special "Observe" handling.
290         Option::Iterator iterator;
291         bool             observe;
292 
293         SuccessOrExit(error = iterator.Init(aMessage, kOptionObserve));
294         observe = !iterator.IsDone();
295 
296         // Special case, if we're sending a GET with Observe=1, that is a cancellation.
297         if (observe && aMessage.IsGetRequest())
298         {
299             uint64_t observeVal = 0;
300 
301             SuccessOrExit(error = iterator.ReadOptionValue(observeVal));
302 
303             if (observeVal == 1)
304             {
305                 Metadata handlerMetadata;
306 
307                 // We're cancelling our subscription, so disable special-case handling on this request.
308                 observe = false;
309 
310                 // If we can find the previous handler context, cancel that too.  Peer address
311                 // and tokens, etc should all match.
312                 Message *origRequest = FindRelatedRequest(aMessage, aMessageInfo, handlerMetadata);
313                 if (origRequest != nullptr)
314                 {
315                     FinalizeCoapTransaction(*origRequest, handlerMetadata, nullptr, nullptr, kErrorNone);
316                 }
317             }
318         }
319 #endif // OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
320 
321         metadata.mSourceAddress            = aMessageInfo.GetSockAddr();
322         metadata.mDestinationPort          = aMessageInfo.GetPeerPort();
323         metadata.mDestinationAddress       = aMessageInfo.GetPeerAddr();
324         metadata.mMulticastLoop            = aMessageInfo.GetMulticastLoop();
325         metadata.mResponseHandler          = aHandler;
326         metadata.mResponseContext          = aContext;
327         metadata.mRetransmissionsRemaining = aTxParameters.mMaxRetransmit;
328         metadata.mRetransmissionTimeout    = aTxParameters.CalculateInitialRetransmissionTimeout();
329         metadata.mAcknowledged             = false;
330         metadata.mConfirmable              = aMessage.IsConfirmable();
331 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
332         metadata.mHopLimit        = aMessageInfo.GetHopLimit();
333         metadata.mIsHostInterface = aMessageInfo.IsHostInterface();
334 #endif
335 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
336         metadata.mBlockwiseReceiveHook  = aReceiveHook;
337         metadata.mBlockwiseTransmitHook = aTransmitHook;
338 #endif
339 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
340         metadata.mObserve = observe;
341 #endif
342         metadata.mNextTimerShot =
343             TimerMilli::GetNow() +
344             (metadata.mConfirmable ? metadata.mRetransmissionTimeout : aTxParameters.CalculateMaxTransmitWait());
345 
346         storedCopy = CopyAndEnqueueMessage(aMessage, copyLength, metadata);
347         VerifyOrExit(storedCopy != nullptr, error = kErrorNoBufs);
348     }
349 
350     SuccessOrExit(error = Send(aMessage, aMessageInfo));
351 
352 exit:
353 
354     if (error != kErrorNone && storedCopy != nullptr)
355     {
356         DequeueMessage(*storedCopy);
357     }
358 
359     return error;
360 }
361 
SendMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const TxParameters & aTxParameters)362 Error CoapBase::SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const TxParameters &aTxParameters)
363 {
364     return SendMessage(aMessage, aMessageInfo, aTxParameters, nullptr, nullptr);
365 }
366 
SendMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,ResponseHandler aHandler,void * aContext)367 Error CoapBase::SendMessage(Message                &aMessage,
368                             const Ip6::MessageInfo &aMessageInfo,
369                             ResponseHandler         aHandler,
370                             void                   *aContext)
371 {
372 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
373     return SendMessage(aMessage, aMessageInfo, TxParameters::GetDefault(), aHandler, aContext, nullptr, nullptr);
374 #else
375     return SendMessage(aMessage, aMessageInfo, TxParameters::GetDefault(), aHandler, aContext);
376 #endif
377 }
378 
SendMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)379 Error CoapBase::SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
380 {
381     return SendMessage(aMessage, aMessageInfo, nullptr, nullptr);
382 }
383 
SendReset(Message & aRequest,const Ip6::MessageInfo & aMessageInfo)384 Error CoapBase::SendReset(Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
385 {
386     return SendEmptyMessage(kTypeReset, aRequest, aMessageInfo);
387 }
388 
SendAck(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)389 Error CoapBase::SendAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
390 {
391     return SendEmptyMessage(kTypeAck, aRequest, aMessageInfo);
392 }
393 
SendEmptyAck(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo,Code aCode)394 Error CoapBase::SendEmptyAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo, Code aCode)
395 {
396     return (aRequest.IsConfirmable() ? SendHeaderResponse(aCode, aRequest, aMessageInfo) : kErrorInvalidArgs);
397 }
398 
SendEmptyAck(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)399 Error CoapBase::SendEmptyAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
400 {
401     return SendEmptyAck(aRequest, aMessageInfo, kCodeChanged);
402 }
403 
SendNotFound(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)404 Error CoapBase::SendNotFound(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
405 {
406     return SendHeaderResponse(kCodeNotFound, aRequest, aMessageInfo);
407 }
408 
SendEmptyMessage(Type aType,const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)409 Error CoapBase::SendEmptyMessage(Type aType, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
410 {
411     Error    error   = kErrorNone;
412     Message *message = nullptr;
413 
414     VerifyOrExit(aRequest.IsConfirmable(), error = kErrorInvalidArgs);
415 
416     VerifyOrExit((message = NewMessage()) != nullptr, error = kErrorNoBufs);
417 
418     message->Init(aType, kCodeEmpty);
419     message->SetMessageId(aRequest.GetMessageId());
420 
421     message->Finish();
422     SuccessOrExit(error = Send(*message, aMessageInfo));
423 
424 exit:
425     FreeMessageOnError(message, error);
426     return error;
427 }
428 
SendHeaderResponse(Message::Code aCode,const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)429 Error CoapBase::SendHeaderResponse(Message::Code aCode, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
430 {
431     Error    error   = kErrorNone;
432     Message *message = nullptr;
433 
434     VerifyOrExit(aRequest.IsRequest(), error = kErrorInvalidArgs);
435     VerifyOrExit((message = NewMessage()) != nullptr, error = kErrorNoBufs);
436 
437     switch (aRequest.GetType())
438     {
439     case kTypeConfirmable:
440         message->Init(kTypeAck, aCode);
441         message->SetMessageId(aRequest.GetMessageId());
442         break;
443 
444     case kTypeNonConfirmable:
445         message->Init(kTypeNonConfirmable, aCode);
446         break;
447 
448     default:
449         ExitNow(error = kErrorInvalidArgs);
450     }
451 
452     SuccessOrExit(error = message->SetTokenFromMessage(aRequest));
453 
454     SuccessOrExit(error = SendMessage(*message, aMessageInfo));
455 
456 exit:
457     FreeMessageOnError(message, error);
458     return error;
459 }
460 
HandleRetransmissionTimer(Timer & aTimer)461 void CoapBase::HandleRetransmissionTimer(Timer &aTimer)
462 {
463     static_cast<Coap *>(static_cast<TimerMilliContext &>(aTimer).GetContext())->HandleRetransmissionTimer();
464 }
465 
HandleRetransmissionTimer(void)466 void CoapBase::HandleRetransmissionTimer(void)
467 {
468     NextFireTime     nextTime;
469     Metadata         metadata;
470     Ip6::MessageInfo messageInfo;
471 
472     for (Message &message : mPendingRequests)
473     {
474         metadata.ReadFrom(message);
475 
476         if (nextTime.GetNow() >= metadata.mNextTimerShot)
477         {
478 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
479             if (message.IsRequest() && metadata.mObserve && metadata.mAcknowledged)
480             {
481                 // This is a RFC7641 subscription.  Do not time out.
482                 continue;
483             }
484 #endif
485 
486             if (!metadata.mConfirmable || (metadata.mRetransmissionsRemaining == 0))
487             {
488                 // No expected response or acknowledgment.
489                 FinalizeCoapTransaction(message, metadata, nullptr, nullptr, kErrorResponseTimeout);
490                 continue;
491             }
492 
493             // Increment retransmission counter and timer.
494             metadata.mRetransmissionsRemaining--;
495             metadata.mRetransmissionTimeout *= 2;
496             metadata.mNextTimerShot = nextTime.GetNow() + metadata.mRetransmissionTimeout;
497             metadata.UpdateIn(message);
498 
499             // Retransmit
500             if (!metadata.mAcknowledged)
501             {
502                 messageInfo.SetPeerAddr(metadata.mDestinationAddress);
503                 messageInfo.SetPeerPort(metadata.mDestinationPort);
504                 messageInfo.SetSockAddr(metadata.mSourceAddress);
505 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
506                 messageInfo.SetHopLimit(metadata.mHopLimit);
507                 messageInfo.SetIsHostInterface(metadata.mIsHostInterface);
508 #endif
509                 messageInfo.SetMulticastLoop(metadata.mMulticastLoop);
510 
511                 SendCopy(message, messageInfo);
512             }
513         }
514 
515         nextTime.UpdateIfEarlier(metadata.mNextTimerShot);
516     }
517 
518     mRetransmissionTimer.FireAt(nextTime);
519 }
520 
FinalizeCoapTransaction(Message & aRequest,const Metadata & aMetadata,Message * aResponse,const Ip6::MessageInfo * aMessageInfo,Error aResult)521 void CoapBase::FinalizeCoapTransaction(Message                &aRequest,
522                                        const Metadata         &aMetadata,
523                                        Message                *aResponse,
524                                        const Ip6::MessageInfo *aMessageInfo,
525                                        Error                   aResult)
526 {
527     DequeueMessage(aRequest);
528 
529     if (aMetadata.mResponseHandler != nullptr)
530     {
531         aMetadata.mResponseHandler(aMetadata.mResponseContext, aResponse, aMessageInfo, aResult);
532     }
533 }
534 
AbortTransaction(ResponseHandler aHandler,void * aContext)535 Error CoapBase::AbortTransaction(ResponseHandler aHandler, void *aContext)
536 {
537     Error    error = kErrorNotFound;
538     Metadata metadata;
539 
540     for (Message &message : mPendingRequests)
541     {
542         metadata.ReadFrom(message);
543 
544         if (metadata.mResponseHandler == aHandler && metadata.mResponseContext == aContext)
545         {
546             FinalizeCoapTransaction(message, metadata, nullptr, nullptr, kErrorAbort);
547             error = kErrorNone;
548         }
549     }
550 
551     return error;
552 }
553 
CopyAndEnqueueMessage(const Message & aMessage,uint16_t aCopyLength,const Metadata & aMetadata)554 Message *CoapBase::CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopyLength, const Metadata &aMetadata)
555 {
556     Error    error       = kErrorNone;
557     Message *messageCopy = nullptr;
558 
559     VerifyOrExit((messageCopy = aMessage.Clone(aCopyLength)) != nullptr, error = kErrorNoBufs);
560 
561     SuccessOrExit(error = aMetadata.AppendTo(*messageCopy));
562 
563     mRetransmissionTimer.FireAtIfEarlier(aMetadata.mNextTimerShot);
564 
565     mPendingRequests.Enqueue(*messageCopy);
566 
567 exit:
568     FreeAndNullMessageOnError(messageCopy, error);
569     return messageCopy;
570 }
571 
DequeueMessage(Message & aMessage)572 void CoapBase::DequeueMessage(Message &aMessage)
573 {
574     mPendingRequests.Dequeue(aMessage);
575 
576     if (mRetransmissionTimer.IsRunning() && (mPendingRequests.GetHead() == nullptr))
577     {
578         mRetransmissionTimer.Stop();
579     }
580 
581     aMessage.Free();
582 
583     // No need to worry that the earliest pending message was removed -
584     // the timer would just shoot earlier and then it'd be setup again.
585 }
586 
587 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
FreeLastBlockResponse(void)588 void CoapBase::FreeLastBlockResponse(void)
589 {
590     if (mLastResponse != nullptr)
591     {
592         mLastResponse->Free();
593         mLastResponse = nullptr;
594     }
595 }
596 
CacheLastBlockResponse(Message * aResponse)597 Error CoapBase::CacheLastBlockResponse(Message *aResponse)
598 {
599     Error error = kErrorNone;
600     // Save last response for block-wise transfer
601     FreeLastBlockResponse();
602 
603     if ((mLastResponse = aResponse->Clone()) == nullptr)
604     {
605         error = kErrorNoBufs;
606     }
607 
608     return error;
609 }
610 
PrepareNextBlockRequest(Message::BlockType aType,bool aMoreBlocks,Message & aRequestOld,Message & aRequest,Message & aMessage)611 Error CoapBase::PrepareNextBlockRequest(Message::BlockType aType,
612                                         bool               aMoreBlocks,
613                                         Message           &aRequestOld,
614                                         Message           &aRequest,
615                                         Message           &aMessage)
616 {
617     Error            error       = kErrorNone;
618     bool             isOptionSet = false;
619     uint16_t         blockOption = 0;
620     Option::Iterator iterator;
621 
622     blockOption = (aType == Message::kBlockType1) ? kOptionBlock1 : kOptionBlock2;
623 
624     aRequest.Init(kTypeConfirmable, static_cast<ot::Coap::Code>(aRequestOld.GetCode()));
625     SuccessOrExit(error = iterator.Init(aRequestOld));
626 
627     // Copy options from last response to next message
628     for (; !iterator.IsDone() && iterator.GetOption()->GetLength() != 0; error = iterator.Advance())
629     {
630         uint16_t optionNumber = iterator.GetOption()->GetNumber();
631 
632         SuccessOrExit(error);
633 
634         // Check if option to copy next is higher than or equal to Block1 option
635         if (optionNumber >= blockOption && !isOptionSet)
636         {
637             // Write Block1 option to next message
638             SuccessOrExit(error = aRequest.AppendBlockOption(aType, aMessage.GetBlockWiseBlockNumber() + 1, aMoreBlocks,
639                                                              aMessage.GetBlockWiseBlockSize()));
640             aRequest.SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber() + 1);
641             aRequest.SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
642             aRequest.SetMoreBlocksFlag(aMoreBlocks);
643 
644             isOptionSet = true;
645 
646             // If option to copy next is Block1 or Block2 option, option is not copied
647             if (optionNumber == kOptionBlock1 || optionNumber == kOptionBlock2)
648             {
649                 continue;
650             }
651         }
652 
653         // Copy option
654         SuccessOrExit(error = aRequest.AppendOptionFromMessage(optionNumber, iterator.GetOption()->GetLength(),
655                                                                iterator.GetMessage(),
656                                                                iterator.GetOptionValueMessageOffset()));
657     }
658 
659     if (!isOptionSet)
660     {
661         // Write Block1 option to next message
662         SuccessOrExit(error = aRequest.AppendBlockOption(aType, aMessage.GetBlockWiseBlockNumber() + 1, aMoreBlocks,
663                                                          aMessage.GetBlockWiseBlockSize()));
664         aRequest.SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber() + 1);
665         aRequest.SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
666         aRequest.SetMoreBlocksFlag(aMoreBlocks);
667     }
668 
669 exit:
670     return error;
671 }
672 
SendNextBlock1Request(Message & aRequest,Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Metadata & aCoapMetadata)673 Error CoapBase::SendNextBlock1Request(Message                &aRequest,
674                                       Message                &aMessage,
675                                       const Ip6::MessageInfo &aMessageInfo,
676                                       const Metadata         &aCoapMetadata)
677 {
678     Error    error                = kErrorNone;
679     Message *request              = nullptr;
680     bool     moreBlocks           = false;
681     uint8_t  buf[kMaxBlockLength] = {0};
682     uint16_t bufLen               = kMaxBlockLength;
683 
684     SuccessOrExit(error = aRequest.ReadBlockOptionValues(kOptionBlock1));
685     SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1));
686 
687     // Conclude block-wise transfer if last block has been received
688     if (!aRequest.IsMoreBlocksFlagSet())
689     {
690         FinalizeCoapTransaction(aRequest, aCoapMetadata, &aMessage, &aMessageInfo, kErrorNone);
691         ExitNow();
692     }
693 
694     // Get next block
695     VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
696                  error = kErrorNoBufs);
697 
698     SuccessOrExit(
699         error = aCoapMetadata.mBlockwiseTransmitHook(aCoapMetadata.mResponseContext, buf,
700                                                      otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
701                                                          (aMessage.GetBlockWiseBlockNumber() + 1),
702                                                      &bufLen, &moreBlocks));
703 
704     // Check if block length is valid
705     VerifyOrExit(bufLen <= otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()), error = kErrorInvalidArgs);
706 
707     // Init request for next block
708     VerifyOrExit((request = NewMessage()) != nullptr, error = kErrorNoBufs);
709     SuccessOrExit(error = PrepareNextBlockRequest(Message::kBlockType1, moreBlocks, aRequest, *request, aMessage));
710 
711     SuccessOrExit(error = request->SetPayloadMarker());
712 
713     SuccessOrExit(error = request->AppendBytes(buf, bufLen));
714 
715     DequeueMessage(aRequest);
716 
717     LogInfo("Send Block1 Nr. %d, Size: %d bytes, More Blocks Flag: %d", request->GetBlockWiseBlockNumber(),
718             otCoapBlockSizeFromExponent(request->GetBlockWiseBlockSize()), request->IsMoreBlocksFlagSet());
719 
720     SuccessOrExit(error = SendMessage(*request, aMessageInfo, TxParameters::GetDefault(),
721                                       aCoapMetadata.mResponseHandler, aCoapMetadata.mResponseContext,
722                                       aCoapMetadata.mBlockwiseTransmitHook, aCoapMetadata.mBlockwiseReceiveHook));
723 
724 exit:
725     FreeMessageOnError(request, error);
726 
727     return error;
728 }
729 
SendNextBlock2Request(Message & aRequest,Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Metadata & aCoapMetadata,uint32_t aTotalLength,bool aBeginBlock1Transfer)730 Error CoapBase::SendNextBlock2Request(Message                &aRequest,
731                                       Message                &aMessage,
732                                       const Ip6::MessageInfo &aMessageInfo,
733                                       const Metadata         &aCoapMetadata,
734                                       uint32_t                aTotalLength,
735                                       bool                    aBeginBlock1Transfer)
736 {
737     Error    error                = kErrorNone;
738     Message *request              = nullptr;
739     uint8_t  buf[kMaxBlockLength] = {0};
740     uint16_t bufLen               = kMaxBlockLength;
741 
742     SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2));
743 
744     // Check payload and block length
745     VerifyOrExit((aMessage.GetLength() - aMessage.GetOffset()) <=
746                          otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) &&
747                      (aMessage.GetLength() - aMessage.GetOffset()) <= kMaxBlockLength,
748                  error = kErrorNoBufs);
749 
750     // Read and then forward payload to receive hook function
751     bufLen = aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
752     SuccessOrExit(
753         error = aCoapMetadata.mBlockwiseReceiveHook(aCoapMetadata.mResponseContext, buf,
754                                                     otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
755                                                         aMessage.GetBlockWiseBlockNumber(),
756                                                     bufLen, aMessage.IsMoreBlocksFlagSet(), aTotalLength));
757 
758     // CoAP Block-Wise Transfer continues
759     LogInfo("Received Block2 Nr. %d , Size: %d bytes, More Blocks Flag: %d", aMessage.GetBlockWiseBlockNumber(),
760             otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()), aMessage.IsMoreBlocksFlagSet());
761 
762     // Conclude block-wise transfer if last block has been received
763     if (!aMessage.IsMoreBlocksFlagSet())
764     {
765         FinalizeCoapTransaction(aRequest, aCoapMetadata, &aMessage, &aMessageInfo, kErrorNone);
766         ExitNow();
767     }
768 
769     // Init request for next block
770     VerifyOrExit((request = NewMessage()) != nullptr, error = kErrorNoBufs);
771     SuccessOrExit(error = PrepareNextBlockRequest(Message::kBlockType2, aMessage.IsMoreBlocksFlagSet(), aRequest,
772                                                   *request, aMessage));
773 
774     if (!aBeginBlock1Transfer)
775     {
776         DequeueMessage(aRequest);
777     }
778 
779     LogInfo("Request Block2 Nr. %d, Size: %d bytes", request->GetBlockWiseBlockNumber(),
780             otCoapBlockSizeFromExponent(request->GetBlockWiseBlockSize()));
781 
782     SuccessOrExit(error =
783                       SendMessage(*request, aMessageInfo, TxParameters::GetDefault(), aCoapMetadata.mResponseHandler,
784                                   aCoapMetadata.mResponseContext, nullptr, aCoapMetadata.mBlockwiseReceiveHook));
785 
786 exit:
787     FreeMessageOnError(request, error);
788 
789     return error;
790 }
791 
ProcessBlock1Request(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const ResourceBlockWise & aResource,uint32_t aTotalLength)792 Error CoapBase::ProcessBlock1Request(Message                 &aMessage,
793                                      const Ip6::MessageInfo  &aMessageInfo,
794                                      const ResourceBlockWise &aResource,
795                                      uint32_t                 aTotalLength)
796 {
797     Error    error                = kErrorNone;
798     Message *response             = nullptr;
799     uint8_t  buf[kMaxBlockLength] = {0};
800     uint16_t bufLen               = kMaxBlockLength;
801 
802     SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1));
803 
804     // Read and then forward payload to receive hook function
805     VerifyOrExit((aMessage.GetLength() - aMessage.GetOffset()) <= kMaxBlockLength, error = kErrorNoBufs);
806     bufLen = aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
807     SuccessOrExit(error = aResource.HandleBlockReceive(buf,
808                                                        otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
809                                                            aMessage.GetBlockWiseBlockNumber(),
810                                                        bufLen, aMessage.IsMoreBlocksFlagSet(), aTotalLength));
811 
812     if (aMessage.IsMoreBlocksFlagSet())
813     {
814         // Set up next response
815         VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorFailed);
816         response->Init(kTypeAck, kCodeContinue);
817         response->SetMessageId(aMessage.GetMessageId());
818         IgnoreReturnValue(response->SetToken(AsConst(aMessage).GetToken(), aMessage.GetTokenLength()));
819 
820         response->SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber());
821         response->SetMoreBlocksFlag(aMessage.IsMoreBlocksFlagSet());
822         response->SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
823 
824         SuccessOrExit(error = response->AppendBlockOption(Message::kBlockType1, response->GetBlockWiseBlockNumber(),
825                                                           response->IsMoreBlocksFlagSet(),
826                                                           response->GetBlockWiseBlockSize()));
827 
828         SuccessOrExit(error = CacheLastBlockResponse(response));
829 
830         LogInfo("Acknowledge Block1 Nr. %d, Size: %d bytes", response->GetBlockWiseBlockNumber(),
831                 otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize()));
832 
833         SuccessOrExit(error = SendMessage(*response, aMessageInfo));
834 
835         error = kErrorBusy;
836     }
837     else
838     {
839         // Conclude block-wise transfer if last block has been received
840         FreeLastBlockResponse();
841         error = kErrorNone;
842     }
843 
844 exit:
845     if (error != kErrorNone && error != kErrorBusy && response != nullptr)
846     {
847         response->Free();
848     }
849 
850     return error;
851 }
852 
ProcessBlock2Request(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const ResourceBlockWise & aResource)853 Error CoapBase::ProcessBlock2Request(Message                 &aMessage,
854                                      const Ip6::MessageInfo  &aMessageInfo,
855                                      const ResourceBlockWise &aResource)
856 {
857     Error            error                = kErrorNone;
858     Message         *response             = nullptr;
859     uint8_t          buf[kMaxBlockLength] = {0};
860     uint16_t         bufLen               = kMaxBlockLength;
861     bool             moreBlocks           = false;
862     uint64_t         optionBuf            = 0;
863     Option::Iterator iterator;
864 
865     SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2));
866 
867     LogInfo("Request for Block2 Nr. %d, Size: %d bytes received", aMessage.GetBlockWiseBlockNumber(),
868             otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()));
869 
870     if (aMessage.GetBlockWiseBlockNumber() == 0)
871     {
872         aResource.HandleRequest(aMessage, aMessageInfo);
873         ExitNow();
874     }
875 
876     // Set up next response
877     VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorNoBufs);
878     response->Init(kTypeAck, kCodeContent);
879     response->SetMessageId(aMessage.GetMessageId());
880 
881     SuccessOrExit(error = response->SetTokenFromMessage(aMessage));
882 
883     VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
884                  error = kErrorNoBufs);
885     SuccessOrExit(error = aResource.HandleBlockTransmit(buf,
886                                                         otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
887                                                             aMessage.GetBlockWiseBlockNumber(),
888                                                         &bufLen, &moreBlocks));
889 
890     response->SetMoreBlocksFlag(moreBlocks);
891     if (moreBlocks)
892     {
893         switch (bufLen)
894         {
895         case 1024:
896             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_1024);
897             break;
898         case 512:
899             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_512);
900             break;
901         case 256:
902             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_256);
903             break;
904         case 128:
905             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_128);
906             break;
907         case 64:
908             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_64);
909             break;
910         case 32:
911             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_32);
912             break;
913         case 16:
914             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_16);
915             break;
916         default:
917             error = kErrorInvalidArgs;
918             ExitNow();
919             break;
920         }
921     }
922     else
923     {
924         // Verify that buffer length is not larger than requested block size
925         VerifyOrExit(bufLen <= otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()),
926                      error = kErrorInvalidArgs);
927         response->SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
928     }
929 
930     response->SetBlockWiseBlockNumber(
931         (otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) * aMessage.GetBlockWiseBlockNumber()) /
932         (otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize())));
933 
934     // Copy options from last response
935     SuccessOrExit(error = iterator.Init(*mLastResponse));
936 
937     while (!iterator.IsDone())
938     {
939         uint16_t optionNumber = iterator.GetOption()->GetNumber();
940 
941         if (optionNumber == kOptionBlock2)
942         {
943             SuccessOrExit(error = response->AppendBlockOption(Message::kBlockType2, response->GetBlockWiseBlockNumber(),
944                                                               response->IsMoreBlocksFlagSet(),
945                                                               response->GetBlockWiseBlockSize()));
946         }
947         else if (optionNumber == kOptionBlock1)
948         {
949             SuccessOrExit(error = iterator.ReadOptionValue(&optionBuf));
950             SuccessOrExit(error = response->AppendOption(optionNumber, iterator.GetOption()->GetLength(), &optionBuf));
951         }
952 
953         SuccessOrExit(error = iterator.Advance());
954     }
955 
956     SuccessOrExit(error = response->SetPayloadMarker());
957     SuccessOrExit(error = response->AppendBytes(buf, bufLen));
958 
959     if (response->IsMoreBlocksFlagSet())
960     {
961         SuccessOrExit(error = CacheLastBlockResponse(response));
962     }
963     else
964     {
965         // Conclude block-wise transfer if last block has been received
966         FreeLastBlockResponse();
967     }
968 
969     LogInfo("Send Block2 Nr. %d, Size: %d bytes, More Blocks Flag %d", response->GetBlockWiseBlockNumber(),
970             otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize()), response->IsMoreBlocksFlagSet());
971 
972     SuccessOrExit(error = SendMessage(*response, aMessageInfo));
973 
974 exit:
975     FreeMessageOnError(response, error);
976 
977     return error;
978 }
979 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
980 
SendCopy(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo)981 void CoapBase::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
982 {
983     Error    error;
984     Message *messageCopy = nullptr;
985 
986     // Create a message copy for lower layers.
987     messageCopy = aMessage.Clone(aMessage.GetLength() - sizeof(Metadata));
988     VerifyOrExit(messageCopy != nullptr, error = kErrorNoBufs);
989 
990     SuccessOrExit(error = Send(*messageCopy, aMessageInfo));
991 
992 exit:
993 
994     if (error != kErrorNone)
995     {
996         LogWarn("Failed to send copy: %s", ErrorToString(error));
997         FreeMessage(messageCopy);
998     }
999 }
1000 
FindRelatedRequest(const Message & aResponse,const Ip6::MessageInfo & aMessageInfo,Metadata & aMetadata)1001 Message *CoapBase::FindRelatedRequest(const Message          &aResponse,
1002                                       const Ip6::MessageInfo &aMessageInfo,
1003                                       Metadata               &aMetadata)
1004 {
1005     Message *request = nullptr;
1006 
1007     for (Message &message : mPendingRequests)
1008     {
1009         aMetadata.ReadFrom(message);
1010 
1011         if (((aMetadata.mDestinationAddress == aMessageInfo.GetPeerAddr()) ||
1012              aMetadata.mDestinationAddress.IsMulticast() ||
1013              aMetadata.mDestinationAddress.GetIid().IsAnycastLocator()) &&
1014             (aMetadata.mDestinationPort == aMessageInfo.GetPeerPort()))
1015         {
1016             switch (aResponse.GetType())
1017             {
1018             case kTypeReset:
1019             case kTypeAck:
1020                 if (aResponse.GetMessageId() == message.GetMessageId())
1021                 {
1022                     request = &message;
1023                     ExitNow();
1024                 }
1025 
1026                 break;
1027 
1028             case kTypeConfirmable:
1029             case kTypeNonConfirmable:
1030                 if (aResponse.IsTokenEqual(message))
1031                 {
1032                     request = &message;
1033                     ExitNow();
1034                 }
1035 
1036                 break;
1037             }
1038         }
1039     }
1040 
1041 exit:
1042     return request;
1043 }
1044 
Receive(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1045 void CoapBase::Receive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1046 {
1047     Message &message = AsCoapMessage(&aMessage);
1048 
1049     if (message.ParseHeader() != kErrorNone)
1050     {
1051         LogDebg("Failed to parse CoAP header");
1052 
1053         if (!aMessageInfo.GetSockAddr().IsMulticast() && message.IsConfirmable())
1054         {
1055             IgnoreError(SendReset(message, aMessageInfo));
1056         }
1057     }
1058     else if (message.IsRequest())
1059     {
1060         ProcessReceivedRequest(message, aMessageInfo);
1061     }
1062     else
1063     {
1064         ProcessReceivedResponse(message, aMessageInfo);
1065     }
1066 
1067 #if OPENTHREAD_CONFIG_OTNS_ENABLE
1068     Get<Utils::Otns>().EmitCoapReceive(message, aMessageInfo);
1069 #endif
1070 }
1071 
ProcessReceivedResponse(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1072 void CoapBase::ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1073 {
1074     Metadata metadata;
1075     Message *request = nullptr;
1076     Error    error   = kErrorNone;
1077 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1078     bool responseObserve = false;
1079 #endif
1080 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1081     uint8_t  blockOptionType   = 0;
1082     uint32_t totalTransferSize = 0;
1083 #endif
1084 
1085     request = FindRelatedRequest(aMessage, aMessageInfo, metadata);
1086     VerifyOrExit(request != nullptr);
1087 
1088 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1089     if (metadata.mObserve && request->IsRequest())
1090     {
1091         // We sent Observe in our request, see if we received Observe in the response too.
1092         Option::Iterator iterator;
1093 
1094         SuccessOrExit(error = iterator.Init(aMessage, kOptionObserve));
1095         responseObserve = !iterator.IsDone();
1096     }
1097 #endif
1098 
1099     switch (aMessage.GetType())
1100     {
1101     case kTypeReset:
1102         if (aMessage.IsEmpty())
1103         {
1104             FinalizeCoapTransaction(*request, metadata, nullptr, nullptr, kErrorAbort);
1105         }
1106 
1107         // Silently ignore non-empty reset messages (RFC 7252, p. 4.2).
1108         break;
1109 
1110     case kTypeAck:
1111         if (aMessage.IsEmpty())
1112         {
1113             // Empty acknowledgment.
1114 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1115             if (metadata.mObserve && !request->IsRequest())
1116             {
1117                 // This is the ACK to our RFC7641 notification.  There will be no
1118                 // "separate" response so pass it back as if it were a piggy-backed
1119                 // response so we can stop re-sending and the application can move on.
1120                 FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, kErrorNone);
1121             }
1122             else
1123 #endif
1124             {
1125                 // This is not related to RFC7641 or the outgoing "request" was not a
1126                 // notification.
1127                 if (metadata.mConfirmable)
1128                 {
1129                     metadata.mAcknowledged = true;
1130                     metadata.UpdateIn(*request);
1131                 }
1132 
1133                 // Remove the message if response is not expected, otherwise await
1134                 // response.
1135                 if (metadata.mResponseHandler == nullptr)
1136                 {
1137                     DequeueMessage(*request);
1138                 }
1139             }
1140         }
1141         else if (aMessage.IsResponse() && aMessage.IsTokenEqual(*request))
1142         {
1143             // Piggybacked response.  If there's an Observe option present in both
1144             // request and response, and we have a response handler; then we're
1145             // dealing with RFC7641 rules here.
1146             // (If there is no response handler, then we're wasting our time!)
1147 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1148             if (metadata.mObserve && responseObserve && (metadata.mResponseHandler != nullptr))
1149             {
1150                 // This is a RFC7641 notification.  The request is *not* done!
1151                 metadata.mResponseHandler(metadata.mResponseContext, &aMessage, &aMessageInfo, kErrorNone);
1152 
1153                 // Consider the message acknowledged at this point.
1154                 metadata.mAcknowledged = true;
1155                 metadata.UpdateIn(*request);
1156             }
1157             else
1158 #endif
1159 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1160             {
1161                 if (metadata.mBlockwiseTransmitHook != nullptr || metadata.mBlockwiseReceiveHook != nullptr)
1162                 {
1163                     // Search for CoAP Block-Wise Option [RFC7959]
1164                     Option::Iterator iterator;
1165 
1166                     SuccessOrExit(error = iterator.Init(aMessage));
1167                     while (!iterator.IsDone())
1168                     {
1169                         switch (iterator.GetOption()->GetNumber())
1170                         {
1171                         case kOptionBlock1:
1172                             blockOptionType += 1;
1173                             break;
1174 
1175                         case kOptionBlock2:
1176                             blockOptionType += 2;
1177                             break;
1178 
1179                         case kOptionSize2:
1180                             // ToDo: wait for method to read uint option values
1181                             totalTransferSize = 0;
1182                             break;
1183 
1184                         default:
1185                             break;
1186                         }
1187 
1188                         SuccessOrExit(error = iterator.Advance());
1189                     }
1190                 }
1191                 switch (blockOptionType)
1192                 {
1193                 case 0:
1194                     // Piggybacked response.
1195                     FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, kErrorNone);
1196                     break;
1197                 case 1: // Block1 option
1198                     if (aMessage.GetCode() == kCodeContinue && metadata.mBlockwiseTransmitHook != nullptr)
1199                     {
1200                         error = SendNextBlock1Request(*request, aMessage, aMessageInfo, metadata);
1201                     }
1202 
1203                     if (aMessage.GetCode() != kCodeContinue || metadata.mBlockwiseTransmitHook == nullptr ||
1204                         error != kErrorNone)
1205                     {
1206                         FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
1207                     }
1208                     break;
1209                 case 2: // Block2 option
1210                     if (aMessage.GetCode() < kCodeBadRequest && metadata.mBlockwiseReceiveHook != nullptr)
1211                     {
1212                         error =
1213                             SendNextBlock2Request(*request, aMessage, aMessageInfo, metadata, totalTransferSize, false);
1214                     }
1215 
1216                     if (aMessage.GetCode() >= kCodeBadRequest || metadata.mBlockwiseReceiveHook == nullptr ||
1217                         error != kErrorNone)
1218                     {
1219                         FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
1220                     }
1221                     break;
1222                 case 3: // Block1 & Block2 option
1223                     if (aMessage.GetCode() < kCodeBadRequest && metadata.mBlockwiseReceiveHook != nullptr)
1224                     {
1225                         error =
1226                             SendNextBlock2Request(*request, aMessage, aMessageInfo, metadata, totalTransferSize, true);
1227                     }
1228 
1229                     FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
1230                     break;
1231                 default:
1232                     error = kErrorAbort;
1233                     FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
1234                     break;
1235                 }
1236             }
1237 #else  // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1238             {
1239                                   FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, kErrorNone);
1240             }
1241 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1242         }
1243 
1244         // Silently ignore acknowledgments carrying requests (RFC 7252, p. 4.2)
1245         // or with no token match (RFC 7252, p. 5.3.2)
1246         break;
1247 
1248     case kTypeConfirmable:
1249         // Send empty ACK if it is a CON message.
1250         IgnoreError(SendAck(aMessage, aMessageInfo));
1251 
1252         OT_FALL_THROUGH;
1253         // Handling of RFC7641 and multicast is below.
1254     case kTypeNonConfirmable:
1255         // Separate response or observation notification.  If the request was to a multicast
1256         // address, OR both the request and response carry Observe options, then this is NOT
1257         // the final message, we may see multiples.
1258         if ((metadata.mResponseHandler != nullptr) && (metadata.mDestinationAddress.IsMulticast()
1259 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1260                                                        || (metadata.mObserve && responseObserve)
1261 #endif
1262                                                            ))
1263         {
1264             // If multicast non-confirmable request, allow multiple responses
1265             metadata.mResponseHandler(metadata.mResponseContext, &aMessage, &aMessageInfo, kErrorNone);
1266         }
1267         else
1268         {
1269             FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, kErrorNone);
1270         }
1271 
1272         break;
1273     }
1274 
1275 exit:
1276 
1277     if (error == kErrorNone && request == nullptr)
1278     {
1279         if (aMessage.IsConfirmable() || aMessage.IsNonConfirmable())
1280         {
1281             // Successfully parsed a header but no matching request was
1282             // found - reject the message by sending reset.
1283             IgnoreError(SendReset(aMessage, aMessageInfo));
1284         }
1285     }
1286 }
1287 
ProcessReceivedRequest(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1288 void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1289 {
1290     char     uriPath[Message::kMaxReceivedUriPath + 1];
1291     Message *cachedResponse = nullptr;
1292     Error    error          = kErrorNone;
1293 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1294     Option::Iterator iterator;
1295     char            *curUriPath        = uriPath;
1296     uint8_t          blockOptionType   = 0;
1297     uint32_t         totalTransferSize = 0;
1298 #endif
1299 
1300     if (mInterceptor.IsSet())
1301     {
1302         SuccessOrExit(error = mInterceptor.Invoke(aMessage, aMessageInfo));
1303     }
1304 
1305     switch (mResponsesQueue.GetMatchedResponseCopy(aMessage, aMessageInfo, &cachedResponse))
1306     {
1307     case kErrorNone:
1308         cachedResponse->Finish();
1309         error = Send(*cachedResponse, aMessageInfo);
1310         ExitNow();
1311 
1312     case kErrorNoBufs:
1313         error = kErrorNoBufs;
1314         ExitNow();
1315 
1316     case kErrorNotFound:
1317     default:
1318         break;
1319     }
1320 
1321 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1322     SuccessOrExit(error = iterator.Init(aMessage));
1323 
1324     while (!iterator.IsDone())
1325     {
1326         switch (iterator.GetOption()->GetNumber())
1327         {
1328         case kOptionUriPath:
1329             if (curUriPath != uriPath)
1330             {
1331                 *curUriPath++ = '/';
1332             }
1333 
1334             VerifyOrExit(curUriPath + iterator.GetOption()->GetLength() < GetArrayEnd(uriPath), error = kErrorParse);
1335 
1336             IgnoreError(iterator.ReadOptionValue(curUriPath));
1337             curUriPath += iterator.GetOption()->GetLength();
1338             break;
1339 
1340         case kOptionBlock1:
1341             blockOptionType += 1;
1342             break;
1343 
1344         case kOptionBlock2:
1345             blockOptionType += 2;
1346             break;
1347 
1348         case kOptionSize1:
1349             // ToDo: wait for method to read uint option values
1350             totalTransferSize = 0;
1351             break;
1352 
1353         default:
1354             break;
1355         }
1356 
1357         SuccessOrExit(error = iterator.Advance());
1358     }
1359 
1360     curUriPath[0] = '\0';
1361 
1362     for (const ResourceBlockWise &resource : mBlockWiseResources)
1363     {
1364         if (!StringMatch(resource.GetUriPath(), uriPath))
1365         {
1366             continue;
1367         }
1368 
1369         if ((resource.mReceiveHook != nullptr || resource.mTransmitHook != nullptr) && blockOptionType != 0)
1370         {
1371             switch (blockOptionType)
1372             {
1373             case 1:
1374                 if (resource.mReceiveHook != nullptr)
1375                 {
1376                     switch (ProcessBlock1Request(aMessage, aMessageInfo, resource, totalTransferSize))
1377                     {
1378                     case kErrorNone:
1379                         resource.HandleRequest(aMessage, aMessageInfo);
1380                         // Fall through
1381                     case kErrorBusy:
1382                         error = kErrorNone;
1383                         break;
1384                     case kErrorNoBufs:
1385                         IgnoreReturnValue(SendHeaderResponse(kCodeRequestTooLarge, aMessage, aMessageInfo));
1386                         error = kErrorDrop;
1387                         break;
1388                     case kErrorNoFrameReceived:
1389                         IgnoreReturnValue(SendHeaderResponse(kCodeRequestIncomplete, aMessage, aMessageInfo));
1390                         error = kErrorDrop;
1391                         break;
1392                     default:
1393                         IgnoreReturnValue(SendHeaderResponse(kCodeInternalError, aMessage, aMessageInfo));
1394                         error = kErrorDrop;
1395                         break;
1396                     }
1397                 }
1398                 break;
1399             case 2:
1400                 if (resource.mTransmitHook != nullptr)
1401                 {
1402                     if ((error = ProcessBlock2Request(aMessage, aMessageInfo, resource)) != kErrorNone)
1403                     {
1404                         IgnoreReturnValue(SendHeaderResponse(kCodeInternalError, aMessage, aMessageInfo));
1405                         error = kErrorDrop;
1406                     }
1407                 }
1408                 break;
1409             }
1410             ExitNow();
1411         }
1412         else
1413         {
1414             resource.HandleRequest(aMessage, aMessageInfo);
1415             error = kErrorNone;
1416             ExitNow();
1417         }
1418     }
1419 #else
1420     SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath));
1421 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1422 
1423     if ((mResourceHandler != nullptr) && mResourceHandler(*this, uriPath, aMessage, aMessageInfo))
1424     {
1425         error = kErrorNone;
1426         ExitNow();
1427     }
1428 
1429     for (const Resource &resource : mResources)
1430     {
1431         if (StringMatch(resource.mUriPath, uriPath))
1432         {
1433             resource.HandleRequest(aMessage, aMessageInfo);
1434             error = kErrorNone;
1435             ExitNow();
1436         }
1437     }
1438 
1439     if (mDefaultHandler.IsSet())
1440     {
1441         mDefaultHandler.Invoke(&aMessage, &aMessageInfo);
1442         error = kErrorNone;
1443         ExitNow();
1444     }
1445 
1446     error = kErrorNotFound;
1447 
1448 exit:
1449 
1450     if (error != kErrorNone)
1451     {
1452         LogInfo("Failed to process request: %s", ErrorToString(error));
1453 
1454         if (error == kErrorNotFound && !aMessageInfo.GetSockAddr().IsMulticast())
1455         {
1456             IgnoreError(SendNotFound(aMessage, aMessageInfo));
1457         }
1458 
1459         FreeMessage(cachedResponse);
1460     }
1461 }
1462 
ReadFrom(const Message & aMessage)1463 void CoapBase::Metadata::ReadFrom(const Message &aMessage)
1464 {
1465     uint16_t length = aMessage.GetLength();
1466 
1467     OT_ASSERT(length >= sizeof(*this));
1468     IgnoreError(aMessage.Read(length - sizeof(*this), *this));
1469 }
1470 
UpdateIn(Message & aMessage) const1471 void CoapBase::Metadata::UpdateIn(Message &aMessage) const
1472 {
1473     aMessage.Write(aMessage.GetLength() - sizeof(*this), *this);
1474 }
1475 
ResponsesQueue(Instance & aInstance)1476 ResponsesQueue::ResponsesQueue(Instance &aInstance)
1477     : mTimer(aInstance, ResponsesQueue::HandleTimer, this)
1478 {
1479 }
1480 
GetMatchedResponseCopy(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo,Message ** aResponse)1481 Error ResponsesQueue::GetMatchedResponseCopy(const Message          &aRequest,
1482                                              const Ip6::MessageInfo &aMessageInfo,
1483                                              Message               **aResponse)
1484 {
1485     Error          error = kErrorNone;
1486     const Message *cacheResponse;
1487 
1488     cacheResponse = FindMatchedResponse(aRequest, aMessageInfo);
1489     VerifyOrExit(cacheResponse != nullptr, error = kErrorNotFound);
1490 
1491     *aResponse = cacheResponse->Clone(cacheResponse->GetLength() - sizeof(ResponseMetadata));
1492     VerifyOrExit(*aResponse != nullptr, error = kErrorNoBufs);
1493 
1494 exit:
1495     return error;
1496 }
1497 
FindMatchedResponse(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo) const1498 const Message *ResponsesQueue::FindMatchedResponse(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo) const
1499 {
1500     const Message *response = nullptr;
1501 
1502     for (const Message &message : mQueue)
1503     {
1504         if (message.GetMessageId() == aRequest.GetMessageId())
1505         {
1506             ResponseMetadata metadata;
1507 
1508             metadata.ReadFrom(message);
1509 
1510             if ((metadata.mMessageInfo.GetPeerPort() == aMessageInfo.GetPeerPort()) &&
1511                 (metadata.mMessageInfo.GetPeerAddr() == aMessageInfo.GetPeerAddr()))
1512             {
1513                 response = &message;
1514                 break;
1515             }
1516         }
1517     }
1518 
1519     return response;
1520 }
1521 
EnqueueResponse(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const TxParameters & aTxParameters)1522 void ResponsesQueue::EnqueueResponse(Message                &aMessage,
1523                                      const Ip6::MessageInfo &aMessageInfo,
1524                                      const TxParameters     &aTxParameters)
1525 {
1526     Message         *responseCopy;
1527     ResponseMetadata metadata;
1528 
1529     metadata.mDequeueTime = TimerMilli::GetNow() + aTxParameters.CalculateExchangeLifetime();
1530     metadata.mMessageInfo = aMessageInfo;
1531 
1532     VerifyOrExit(FindMatchedResponse(aMessage, aMessageInfo) == nullptr);
1533 
1534     UpdateQueue();
1535 
1536     VerifyOrExit((responseCopy = aMessage.Clone()) != nullptr);
1537 
1538     VerifyOrExit(metadata.AppendTo(*responseCopy) == kErrorNone, responseCopy->Free());
1539 
1540     mQueue.Enqueue(*responseCopy);
1541 
1542     mTimer.FireAtIfEarlier(metadata.mDequeueTime);
1543 
1544 exit:
1545     return;
1546 }
1547 
UpdateQueue(void)1548 void ResponsesQueue::UpdateQueue(void)
1549 {
1550     uint16_t  msgCount    = 0;
1551     Message  *earliestMsg = nullptr;
1552     TimeMilli earliestDequeueTime(0);
1553 
1554     // Check the number of messages in the queue and if number is at
1555     // `kMaxCachedResponses` remove the one with earliest dequeue
1556     // time.
1557 
1558     for (Message &message : mQueue)
1559     {
1560         ResponseMetadata metadata;
1561 
1562         metadata.ReadFrom(message);
1563 
1564         if ((earliestMsg == nullptr) || (metadata.mDequeueTime < earliestDequeueTime))
1565         {
1566             earliestMsg         = &message;
1567             earliestDequeueTime = metadata.mDequeueTime;
1568         }
1569 
1570         msgCount++;
1571     }
1572 
1573     if (msgCount >= kMaxCachedResponses)
1574     {
1575         DequeueResponse(*earliestMsg);
1576     }
1577 }
1578 
DequeueResponse(Message & aMessage)1579 void ResponsesQueue::DequeueResponse(Message &aMessage) { mQueue.DequeueAndFree(aMessage); }
1580 
DequeueAllResponses(void)1581 void ResponsesQueue::DequeueAllResponses(void) { mQueue.DequeueAndFreeAll(); }
1582 
HandleTimer(Timer & aTimer)1583 void ResponsesQueue::HandleTimer(Timer &aTimer)
1584 {
1585     static_cast<ResponsesQueue *>(static_cast<TimerMilliContext &>(aTimer).GetContext())->HandleTimer();
1586 }
1587 
HandleTimer(void)1588 void ResponsesQueue::HandleTimer(void)
1589 {
1590     NextFireTime nextDequeueTime;
1591 
1592     for (Message &message : mQueue)
1593     {
1594         ResponseMetadata metadata;
1595 
1596         metadata.ReadFrom(message);
1597 
1598         if (nextDequeueTime.GetNow() >= metadata.mDequeueTime)
1599         {
1600             DequeueResponse(message);
1601             continue;
1602         }
1603 
1604         nextDequeueTime.UpdateIfEarlier(metadata.mDequeueTime);
1605     }
1606 
1607     mTimer.FireAt(nextDequeueTime);
1608 }
1609 
ReadFrom(const Message & aMessage)1610 void ResponsesQueue::ResponseMetadata::ReadFrom(const Message &aMessage)
1611 {
1612     uint16_t length = aMessage.GetLength();
1613 
1614     OT_ASSERT(length >= sizeof(*this));
1615     IgnoreError(aMessage.Read(length - sizeof(*this), *this));
1616 }
1617 
1618 /// Return product of @p aValueA and @p aValueB if no overflow otherwise 0.
Multiply(uint32_t aValueA,uint32_t aValueB)1619 static uint32_t Multiply(uint32_t aValueA, uint32_t aValueB)
1620 {
1621     uint32_t result = 0;
1622 
1623     VerifyOrExit(aValueA);
1624 
1625     result = aValueA * aValueB;
1626     result = (result / aValueA == aValueB) ? result : 0;
1627 
1628 exit:
1629     return result;
1630 }
1631 
IsValid(void) const1632 bool TxParameters::IsValid(void) const
1633 {
1634     bool rval = false;
1635 
1636     if ((mAckRandomFactorDenominator > 0) && (mAckRandomFactorNumerator >= mAckRandomFactorDenominator) &&
1637         (mAckTimeout >= OT_COAP_MIN_ACK_TIMEOUT) && (mMaxRetransmit <= OT_COAP_MAX_RETRANSMIT))
1638     {
1639         // Calculate exchange lifetime step by step and verify no overflow.
1640         uint32_t tmp = Multiply(mAckTimeout, (1U << (mMaxRetransmit + 1)) - 1);
1641 
1642         tmp = Multiply(tmp, mAckRandomFactorNumerator);
1643         tmp /= mAckRandomFactorDenominator;
1644 
1645         rval = (tmp != 0 && (tmp + mAckTimeout + 2 * kDefaultMaxLatency) > tmp);
1646     }
1647 
1648     return rval;
1649 }
1650 
CalculateInitialRetransmissionTimeout(void) const1651 uint32_t TxParameters::CalculateInitialRetransmissionTimeout(void) const
1652 {
1653     return Random::NonCrypto::GetUint32InRange(
1654         mAckTimeout, mAckTimeout * mAckRandomFactorNumerator / mAckRandomFactorDenominator + 1);
1655 }
1656 
CalculateExchangeLifetime(void) const1657 uint32_t TxParameters::CalculateExchangeLifetime(void) const
1658 {
1659     // Final `mAckTimeout` is to account for processing delay.
1660     return CalculateSpan(mMaxRetransmit) + 2 * kDefaultMaxLatency + mAckTimeout;
1661 }
1662 
CalculateMaxTransmitWait(void) const1663 uint32_t TxParameters::CalculateMaxTransmitWait(void) const { return CalculateSpan(mMaxRetransmit + 1); }
1664 
CalculateSpan(uint8_t aMaxRetx) const1665 uint32_t TxParameters::CalculateSpan(uint8_t aMaxRetx) const
1666 {
1667     return static_cast<uint32_t>(mAckTimeout * ((1U << aMaxRetx) - 1) / mAckRandomFactorDenominator *
1668                                  mAckRandomFactorNumerator);
1669 }
1670 
1671 const otCoapTxParameters TxParameters::kDefaultTxParameters = {
1672     kDefaultAckTimeout,
1673     kDefaultAckRandomFactorNumerator,
1674     kDefaultAckRandomFactorDenominator,
1675     kDefaultMaxRetransmit,
1676 };
1677 
1678 //----------------------------------------------------------------------------------------------------------------------
1679 
Resource(const char * aUriPath,RequestHandler aHandler,void * aContext)1680 Resource::Resource(const char *aUriPath, RequestHandler aHandler, void *aContext)
1681 {
1682     mUriPath = aUriPath;
1683     mHandler = aHandler;
1684     mContext = aContext;
1685     mNext    = nullptr;
1686 }
1687 
Resource(Uri aUri,RequestHandler aHandler,void * aContext)1688 Resource::Resource(Uri aUri, RequestHandler aHandler, void *aContext)
1689     : Resource(PathForUri(aUri), aHandler, aContext)
1690 {
1691 }
1692 
1693 //----------------------------------------------------------------------------------------------------------------------
1694 
Coap(Instance & aInstance)1695 Coap::Coap(Instance &aInstance)
1696     : CoapBase(aInstance, &Coap::Send)
1697     , mSocket(aInstance, *this)
1698 {
1699 }
1700 
Start(uint16_t aPort,Ip6::NetifIdentifier aNetifIdentifier)1701 Error Coap::Start(uint16_t aPort, Ip6::NetifIdentifier aNetifIdentifier)
1702 {
1703     Error error        = kErrorNone;
1704     bool  socketOpened = false;
1705 
1706     VerifyOrExit(!mSocket.IsBound());
1707 
1708     SuccessOrExit(error = mSocket.Open());
1709     socketOpened = true;
1710 
1711     SuccessOrExit(error = mSocket.Bind(aPort, aNetifIdentifier));
1712 
1713 exit:
1714     if (error != kErrorNone && socketOpened)
1715     {
1716         IgnoreError(mSocket.Close());
1717     }
1718 
1719     return error;
1720 }
1721 
Stop(void)1722 Error Coap::Stop(void)
1723 {
1724     Error error = kErrorNone;
1725 
1726     VerifyOrExit(mSocket.IsBound());
1727 
1728     SuccessOrExit(error = mSocket.Close());
1729     ClearRequestsAndResponses();
1730 
1731 exit:
1732     return error;
1733 }
1734 
HandleUdpReceive(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1735 void Coap::HandleUdpReceive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1736 {
1737     Receive(AsCoapMessage(&aMessage), aMessageInfo);
1738 }
1739 
Send(CoapBase & aCoapBase,ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1740 Error Coap::Send(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1741 {
1742     return static_cast<Coap &>(aCoapBase).Send(aMessage, aMessageInfo);
1743 }
1744 
Send(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1745 Error Coap::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1746 {
1747     return mSocket.IsBound() ? mSocket.SendTo(aMessage, aMessageInfo) : kErrorInvalidState;
1748 }
1749 
1750 } // namespace Coap
1751 } // namespace ot
1752