diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index cd931dbb6..bafc8fc9d 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -618,7 +618,7 @@ void CoapBase::ProcessReceivedResponse(Msg &aRxMsg) if (shouldObserve) { // This is a RFC7641 notification. The request is *not* done! - request.InvokeResponseHandler(&aRxMsg, kErrorNone); + mPendingRequests.DispatchResponse(request, kErrorNone, &aRxMsg); request.MarkAsAcknowledged(); ExitNow(); @@ -648,7 +648,7 @@ void CoapBase::ProcessReceivedResponse(Msg &aRxMsg) #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE if (shouldObserve) { - request.InvokeResponseHandler(&aRxMsg, kErrorNone); + mPendingRequests.DispatchResponse(request, kErrorNone, &aRxMsg); // When any Observe response is seen, consider a NON observe // request "acknowledged" at this point. This will keep the @@ -669,7 +669,7 @@ void CoapBase::ProcessReceivedResponse(Msg &aRxMsg) if (request.HasResponseHandler() && request.GetDestinationAddress().IsMulticast()) { - request.InvokeResponseHandler(&aRxMsg, kErrorNone); + mPendingRequests.DispatchResponse(request, kErrorNone, &aRxMsg); } else { @@ -1535,6 +1535,7 @@ bool CoapBase::Request::IsObserveSubscription(void) const CoapBase::PendingRequests::PendingRequests(Instance &aInstance, CoapBase &aCoapBase) : mCoapBase(aCoapBase) + , mDispatchingRequest(nullptr) , mTimer(aInstance, HandleTimer, this) { } @@ -1632,13 +1633,48 @@ void CoapBase::PendingRequests::FinalizeRequest(Request &aRequest, Error aResult { VerifyOrExit(aRequest.HasMessage()); - Remove(aRequest); - aRequest.InvokeResponseHandler(aResponse, aResult); + mRequestMessages.Dequeue(*aRequest.mMessage); + + DispatchResponse(aRequest, aResult, aResponse); + + aRequest.mMessage->Free(); + aRequest.Clear(); exit: return; } +void CoapBase::PendingRequests::DispatchResponse(Request &aRequest, Error aResult) +{ + DispatchResponse(aRequest, aResult, /* aResponse */ nullptr); +} + +void CoapBase::PendingRequests::DispatchResponse(Request &aRequest, Error aResult, Msg *aResponse) +{ + const Request *prev = mDispatchingRequest; + + mDispatchingRequest = &aRequest; + aRequest.GetCallbacks().InvokeResponseHandler(aResponse, aResult); + mDispatchingRequest = prev; +} + +Error CoapBase::PendingRequests::GetDispatchingRequest(OwnedPtr &aMessage) const +{ + Error error = kErrorNotFound; + + VerifyOrExit(mDispatchingRequest != nullptr); + VerifyOrExit(mDispatchingRequest->IsConfirmable()); + VerifyOrExit(mDispatchingRequest->HasMessage()); + + aMessage.Reset(mCoapBase.CloneMessageWithout(mDispatchingRequest->GetMessage())); + VerifyOrExit(aMessage != nullptr, error = kErrorNoBufs); + + error = kErrorNone; + +exit: + return error; +} + void CoapBase::PendingRequests::AbortAllRequests(void) { IgnoreError(AbortAllMatching(Matcher())); @@ -1686,7 +1722,7 @@ void CoapBase::PendingRequests::FinalizeRemovedRequestsIn(MessageQueue &aQueue, Request request; request.InitFrom(message); - request.InvokeResponseHandler(/* aResponse */ nullptr, aResult); + DispatchResponse(request, aResult); } aQueue.DequeueAndFreeAll(); diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp index dedf5c59b..5424398b8 100644 --- a/src/core/coap/coap.hpp +++ b/src/core/coap/coap.hpp @@ -571,6 +571,23 @@ public: */ Error SendMessage(OwnedPtr aMessage, const Ip6::MessageInfo &aMessageInfo); + /** + * Gets a copy of the request message currently being dispatched (`ResponseHandler` callback is invoked). + * + * This method can only be used from a `ResponseHandler` callback. It returns a copy of the original request + * message if the request was confirmable. + * + * @param[out] aMessage A reference to an `OwnedPtr` to return a copy of original request message. + * + * @retval kErrorNone Successfully retrieved and cloned the request message. + * @retval kErrorNotFound Not currently dispatching a confirmable request. + * @retval kErrorNoBufs Failed to allocate a message for the clone. + */ + Error GetDispatchingRequest(OwnedPtr &aMessage) const + { + return mPendingRequests.GetDispatchingRequest(aMessage); + } + /** * Sends an empty CoAP message (using `kCodeEmpty` Code 0.00). * @@ -824,10 +841,6 @@ private: bool ShouldRetransmit(void) const; void UpdateRetxCounterAndTimeout(TimeMilli aNow); bool HasResponseHandler(void) const { return GetCallbacks().HasResponseHandler(); } - void InvokeResponseHandler(Msg *aMsg, Error aResult) const - { - GetCallbacks().InvokeResponseHandler(aMsg, aResult); - } const Message &GetMessage(void) const { return *mMessage; } const Ip6::Address &GetSourceAddress(void) const { return mMetadata.mSourceAddress; } @@ -896,6 +909,9 @@ private: void AbortAllRequests(void); void AbortRequestsMatching(const Ip6::Address &aAddress); Error AbortRequestsMatching(ResponseHandler aHandler, void *aContext); + void DispatchResponse(Request &aRequest, Error aResult, Msg *aResponse); + void DispatchResponse(Request &aRequest, Error aResult); + Error GetDispatchingRequest(OwnedPtr &aMessage) const; void GetInfo(MessageQueue::Info &aInfo) const { mRequestMessages.GetInfo(aInfo); } private: @@ -935,6 +951,7 @@ private: CoapBase &mCoapBase; MessageQueue mRequestMessages; + const Request *mDispatchingRequest; TimerMilliContext mTimer; };