From c650cede5aee548b1e8ab8cb5bd07fe5b41d5958 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 11 May 2026 09:05:46 -0700 Subject: [PATCH] [coap] add mechanism to access request message in response handler (#13081) This commit updates `CoapBase::PendingRequests` to track the request currently being processed during callback invocation via the new `mDispatchingRequest` pointer. It also introduces `GetDispatchingRequest()` which returns a copy of the original request `Message`. This enables response handler callbacks to inspect the original request (for example to read specific TLVs). The method is restricted to confirmable requests and must only be called from within the context of a response handler. The method `InvokeResponseHandler` is renamed to `DispatchResponse` to align with the new nomenclature. --- src/core/coap/coap.cpp | 48 ++++++++++++++++++++++++++++++++++++------ src/core/coap/coap.hpp | 25 ++++++++++++++++++---- 2 files changed, 63 insertions(+), 10 deletions(-) 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; };