[coap] add helper methods to CoapBase::Metadata (#12364)

This commit adds methods to `CoapBase::Metadata` to encapsulate logic
related to initialization, retransmission checks, and updating
retransmission counters. It also renames member variables for brevity
(e.g., `mRetransmissionsRemaining` to `mRetxRemaining`) and moves
`IsObserveSubscription()` to be a method of `Metadata`.

These changes simplify implementation by delegating metadata-specific
operations to the `Metadata` struct itself.
This commit is contained in:
Abtin Keshavarzian
2026-02-04 12:59:11 -08:00
committed by GitHub
parent dd0d8311f8
commit 5144638a63
2 changed files with 106 additions and 81 deletions
+82 -64
View File
@@ -261,7 +261,6 @@ Error CoapBase::SendMessage(Message &aMessage,
Message *storedCopy = nullptr;
uint16_t copyLength = 0;
Msg txMsg(aMessage, aMessageInfo);
Metadata metadata;
SuccessOrExit(error = txMsg.ParseHeaderAndOptions(Msg::kRemovePayloadMarkerIfNoPayload));
@@ -304,33 +303,14 @@ Error CoapBase::SendMessage(Message &aMessage,
if (copyLength > 0)
{
Metadata metadata;
metadata.Init(txMsg, *aTxParameters, aCallbacks);
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
{
bool shouldObserve = false;
SuccessOrExit(error = ProcessObserveSend(txMsg, shouldObserve));
metadata.mObserve = shouldObserve;
metadata.mIsRequest = txMsg.IsRequest();
}
SuccessOrExit(error = ProcessObserveSend(txMsg, metadata));
#endif
metadata.mSourceAddress = txMsg.mMessageInfo.GetSockAddr();
metadata.mDestinationPort = txMsg.mMessageInfo.GetPeerPort();
metadata.mDestinationAddress = txMsg.mMessageInfo.GetPeerAddr();
metadata.mMulticastLoop = txMsg.mMessageInfo.GetMulticastLoop();
metadata.mCallbacks = aCallbacks;
metadata.mRetransmissionsRemaining = aTxParameters->mMaxRetransmit;
metadata.mRetransmissionTimeout = aTxParameters->CalculateInitialRetransmissionTimeout();
metadata.mAcknowledged = false;
metadata.mConfirmable = txMsg.IsConfirmable();
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
metadata.mHopLimit = txMsg.mMessageInfo.GetHopLimit();
metadata.mIsHostInterface = txMsg.mMessageInfo.IsHostInterface();
#endif
metadata.mNextTimerShot =
TimerMilli::GetNow() +
(metadata.mConfirmable ? metadata.mRetransmissionTimeout : aTxParameters->CalculateMaxTransmitWait());
storedCopy = CopyAndEnqueueMessage(txMsg.mMessage, copyLength, metadata);
VerifyOrExit(storedCopy != nullptr, error = kErrorNoBufs);
}
@@ -513,7 +493,7 @@ void CoapBase::ScheduleRetransmissionTimer(void)
metadata.ReadFrom(message);
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
if (IsObserveSubscription(metadata))
if (metadata.IsObserveSubscription())
{
// This is an RFC7641 subscription which is already acknowledged.
// We do not time it out, so skip it when determining the next
@@ -522,7 +502,7 @@ void CoapBase::ScheduleRetransmissionTimer(void)
}
#endif
nextTime.UpdateIfEarlier(metadata.mNextTimerShot);
nextTime.UpdateIfEarlier(metadata.mTimerFireTime);
}
mRetransmissionTimer.FireAt(nextTime);
@@ -543,40 +523,27 @@ void CoapBase::HandleRetransmissionTimer(void)
{
metadata.ReadFrom(message);
if (now >= metadata.mNextTimerShot)
if (now >= metadata.mTimerFireTime)
{
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
if (IsObserveSubscription(metadata))
if (metadata.IsObserveSubscription())
{
continue;
}
#endif
if (!metadata.mConfirmable || (metadata.mRetransmissionsRemaining == 0))
if (!metadata.ShouldRetransmit())
{
// No expected response or acknowledgment.
FinalizeCoapTransaction(message, metadata, nullptr, kErrorResponseTimeout);
continue;
}
// Increment retransmission counter and timer.
metadata.mRetransmissionsRemaining--;
metadata.mRetransmissionTimeout *= 2;
metadata.mNextTimerShot = now + metadata.mRetransmissionTimeout;
metadata.UpdateRetxCounterAndTimeout(now);
metadata.UpdateIn(message);
// Retransmit
if (!metadata.mAcknowledged)
{
messageInfo.SetPeerAddr(metadata.mDestinationAddress);
messageInfo.SetPeerPort(metadata.mDestinationPort);
messageInfo.SetSockAddr(metadata.mSourceAddress);
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
messageInfo.SetHopLimit(metadata.mHopLimit);
messageInfo.SetIsHostInterface(metadata.mIsHostInterface);
#endif
messageInfo.SetMulticastLoop(metadata.mMulticastLoop);
metadata.CopyInfoTo(messageInfo);
SendCopy(message, messageInfo);
}
}
@@ -671,9 +638,8 @@ Message *CoapBase::FindRelatedRequest(const Msg &aMsg, Metadata &aMetadata)
{
aMetadata.ReadFrom(message);
if (((aMetadata.mDestinationAddress == aMsg.mMessageInfo.GetPeerAddr() &&
aMetadata.mDestinationPort == aMsg.mMessageInfo.GetPeerPort()) ||
aMetadata.mDestinationAddress.IsMulticast() || aMetadata.mDestinationAddress.GetIid().IsAnycastLocator()))
if (aMetadata.HasSamePeerAddrAndPort(aMsg.mMessageInfo) || aMetadata.mDestinationAddress.IsMulticast() ||
aMetadata.mDestinationAddress.GetIid().IsAnycastLocator())
{
switch (aMsg.GetType())
{
@@ -1595,20 +1561,21 @@ exit:
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
Error CoapBase::ProcessObserveSend(Msg &aTxMsg, bool &aShouldObserve)
Error CoapBase::ProcessObserveSend(Msg &aTxMsg, Metadata &aMetadata)
{
Error error;
Option::Iterator iterator;
aShouldObserve = false;
aMetadata.mObserve = false;
aMetadata.mIsRequest = aTxMsg.IsRequest();
SuccessOrExit(error = iterator.Init(aTxMsg.mMessage, kOptionObserve));
aShouldObserve = !iterator.IsDone();
aMetadata.mObserve = !iterator.IsDone();
// Special case, if we're sending a GET with Observe=1, that is a
// cancellation.
if (aShouldObserve && aTxMsg.IsGetRequest())
if (aMetadata.mObserve && aTxMsg.IsGetRequest())
{
uint64_t value = 0;
@@ -1617,17 +1584,17 @@ Error CoapBase::ProcessObserveSend(Msg &aTxMsg, bool &aShouldObserve)
if (value == 1)
{
Message *request;
Metadata metadata;
Metadata reqMetadata;
aShouldObserve = false;
aMetadata.mObserve = false;
// If we can find the previous matching request, cancel that too.
request = FindRelatedRequest(aTxMsg, metadata);
request = FindRelatedRequest(aTxMsg, reqMetadata);
if (request != nullptr)
{
FinalizeCoapTransaction(*request, metadata, nullptr, kErrorNone);
FinalizeCoapTransaction(*request, reqMetadata, nullptr, kErrorNone);
}
}
}
@@ -1636,14 +1603,6 @@ exit:
return error;
}
bool CoapBase::IsObserveSubscription(const Metadata &aMetadata)
{
// Indicate whether the message is an RFC7641 subscription which
// is already acknowledged.
return aMetadata.mIsRequest && aMetadata.mObserve && aMetadata.mAcknowledged;
}
#endif // OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
//---------------------------------------------------------------------------------------------------------------------
@@ -1691,6 +1650,65 @@ void CoapBase::SendCallbacks::InvokeResponseHandler(Msg *aMsg, Error aResult) co
}
}
//---------------------------------------------------------------------------------------------------------------------
// CoapBase::Metadata
void CoapBase::Metadata::Init(const Msg &aTxMsg, const TxParameters &aTxParams, const SendCallbacks &aCallbacks)
{
mSourceAddress = aTxMsg.mMessageInfo.GetSockAddr();
mDestinationPort = aTxMsg.mMessageInfo.GetPeerPort();
mDestinationAddress = aTxMsg.mMessageInfo.GetPeerAddr();
mMulticastLoop = aTxMsg.mMessageInfo.GetMulticastLoop();
mCallbacks = aCallbacks;
mRetxRemaining = aTxParams.mMaxRetransmit;
mRetxTimeout = aTxParams.CalculateInitialRetransmissionTimeout();
mAcknowledged = false;
mConfirmable = aTxMsg.IsConfirmable();
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
mHopLimit = aTxMsg.mMessageInfo.GetHopLimit();
mIsHostInterface = aTxMsg.mMessageInfo.IsHostInterface();
#endif
mTimerFireTime = TimerMilli::GetNow() + (mConfirmable ? mRetxTimeout : aTxParams.CalculateMaxTransmitWait());
}
bool CoapBase::Metadata::HasSamePeerAddrAndPort(const Ip6::MessageInfo &aMessageInfo) const
{
return (mDestinationPort == aMessageInfo.GetPeerPort()) && (mDestinationAddress == aMessageInfo.GetPeerAddr());
}
bool CoapBase::Metadata::ShouldRetransmit(void) const { return mConfirmable && (mRetxRemaining > 0); }
void CoapBase::Metadata::UpdateRetxCounterAndTimeout(TimeMilli aNow)
{
mRetxRemaining--;
mRetxTimeout *= 2;
mTimerFireTime = aNow + mRetxTimeout;
}
void CoapBase::Metadata::CopyInfoTo(Ip6::MessageInfo &aMessageInfo) const
{
aMessageInfo.SetPeerAddr(mDestinationAddress);
aMessageInfo.SetPeerPort(mDestinationPort);
aMessageInfo.SetSockAddr(mSourceAddress);
aMessageInfo.SetMulticastLoop(mMulticastLoop);
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
aMessageInfo.SetHopLimit(mHopLimit);
aMessageInfo.SetIsHostInterface(mIsHostInterface);
#endif
}
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
bool CoapBase::Metadata::IsObserveSubscription(void) const
{
// Indicate whether the message is an RFC7641 subscription which
// is already acknowledged.
return mIsRequest && mObserve && mAcknowledged;
}
#endif
//---------------------------------------------------------------------------------------------------------------------
// CoapBase::ResponseCache
+24 -17
View File
@@ -784,24 +784,33 @@ private:
struct Metadata : public Message::FooterData<Metadata>
{
Ip6::Address mSourceAddress; // IPv6 address of the message source.
Ip6::Address mDestinationAddress; // IPv6 address of the message destination.
uint16_t mDestinationPort; // UDP port of the message destination.
SendCallbacks mCallbacks; // All callbacks, response handler and clockwise rx/tx hooks.
TimeMilli mNextTimerShot; // Time when the timer should shoot for this message.
uint32_t mRetransmissionTimeout; // Delay that is applied to next retransmission.
uint8_t mRetransmissionsRemaining; // Number of retransmissions remaining.
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
uint8_t mHopLimit; // The hop limit.
void Init(const Msg &aTxMsg, const TxParameters &aTxParams, const SendCallbacks &aCallbacks);
bool HasSamePeerAddrAndPort(const Ip6::MessageInfo &aMessageInfo) const;
bool ShouldRetransmit(void) const;
void UpdateRetxCounterAndTimeout(TimeMilli aNow);
void CopyInfoTo(Ip6::MessageInfo &aMessageInfo) const;
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
bool IsObserveSubscription(void) const;
#endif
bool mAcknowledged : 1; // Information that request was acknowledged.
bool mConfirmable : 1; // Information that message is confirmable.
bool mMulticastLoop : 1; // Information that multicast loop is enabled.
Ip6::Address mSourceAddress;
Ip6::Address mDestinationAddress;
uint16_t mDestinationPort;
SendCallbacks mCallbacks;
TimeMilli mTimerFireTime;
uint32_t mRetxTimeout;
uint8_t mRetxRemaining;
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
bool mIsHostInterface : 1; // TRUE if packets sent/received via host interface, FALSE otherwise.
uint8_t mHopLimit;
#endif
bool mAcknowledged : 1;
bool mConfirmable : 1;
bool mMulticastLoop : 1;
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
bool mIsHostInterface : 1;
#endif
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
bool mObserve : 1; // Information that this request involves Observations.
bool mObserve : 1;
bool mIsRequest : 1;
#endif
};
@@ -882,9 +891,7 @@ private:
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
Error ProcessObserveSend(Msg &aTxMsg, bool &aShouldObserve);
static bool IsObserveSubscription(const Metadata &aMetadata);
Error ProcessObserveSend(Msg &aTxMsg, Metadata &aMetadata);
#endif
MessageQueue mPendingRequests;