mirror of
https://github.com/espressif/openthread.git
synced 2026-10-09 09:17:37 +00:00
[srp-server] process completed update from proxy from taskelt (#9398)
This commit enhances `Srp::Server` to process and commit the completed `UpdateMetadata` entries (signaled by the "proxy service handler" calling `HandleServiceUpdateResult()`) from a `Tasklet`. This change is helpful in the case where the `HandleServiceUpdateResult ()` callback is invoked directly from the "update service handler" itself. While `Srp::Server` can handle this situation, the change makes it easier for platform implementations of advertising proxy. In particular, it addresses an issue with the `otbr` advertising proxy implementation. This implementation can potentially access an already freed `Host` object. This can happen because the implementation may hold on to the `Host` object while iterating over its `Service` entries as advertising an earlier `Service` of the same `Host` may fail immediately and invoke the callback directly. This would then cause the `Host` to be freed by `Srp::Server`.
This commit is contained in:
@@ -180,6 +180,26 @@ public:
|
|||||||
aPrevEntry.SetNext(&aEntry);
|
aPrevEntry.SetNext(&aEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes an entry after the tail in the linked list.
|
||||||
|
*
|
||||||
|
* @param[in] aEntry A reference to an entry to push into the list.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void PushAfterTail(Type &aEntry)
|
||||||
|
{
|
||||||
|
Type *tail = GetTail();
|
||||||
|
|
||||||
|
if (tail == nullptr)
|
||||||
|
{
|
||||||
|
Push(aEntry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PushAfter(aEntry, *tail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pops an entry from head of the linked list.
|
* Pops an entry from head of the linked list.
|
||||||
*
|
*
|
||||||
|
|||||||
+48
-19
@@ -89,6 +89,7 @@ Server::Server(Instance &aInstance)
|
|||||||
, mSocket(aInstance)
|
, mSocket(aInstance)
|
||||||
, mLeaseTimer(aInstance)
|
, mLeaseTimer(aInstance)
|
||||||
, mOutstandingUpdatesTimer(aInstance)
|
, mOutstandingUpdatesTimer(aInstance)
|
||||||
|
, mCompletedUpdateTask(aInstance)
|
||||||
, mServiceUpdateId(Random::NonCrypto::GetUint32())
|
, mServiceUpdateId(Random::NonCrypto::GetUint32())
|
||||||
, mPort(kUdpPortMin)
|
, mPort(kUdpPortMin)
|
||||||
, mState(kStateDisabled)
|
, mState(kStateDisabled)
|
||||||
@@ -381,26 +382,26 @@ exit:
|
|||||||
|
|
||||||
void Server::HandleServiceUpdateResult(ServiceUpdateId aId, Error aError)
|
void Server::HandleServiceUpdateResult(ServiceUpdateId aId, Error aError)
|
||||||
{
|
{
|
||||||
UpdateMetadata *update = mOutstandingUpdates.FindMatching(aId);
|
UpdateMetadata *update = mOutstandingUpdates.RemoveMatching(aId);
|
||||||
|
|
||||||
if (update != nullptr)
|
if (update == nullptr)
|
||||||
{
|
|
||||||
HandleServiceUpdateResult(update, aError);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
LogInfo("Delayed SRP host update result, the SRP update has been committed (updateId = %lu)", ToUlong(aId));
|
LogInfo("Delayed SRP host update result, the SRP update has been committed (updateId = %lu)", ToUlong(aId));
|
||||||
|
ExitNow();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError)
|
update->SetError(aError);
|
||||||
{
|
|
||||||
LogInfo("Handler result of SRP update (id = %lu) is received: %s", ToUlong(aUpdate->GetId()),
|
|
||||||
ErrorToString(aError));
|
|
||||||
|
|
||||||
IgnoreError(mOutstandingUpdates.Remove(*aUpdate));
|
LogInfo("Handler result of SRP update (id = %lu) is received: %s", ToUlong(update->GetId()), ErrorToString(aError));
|
||||||
CommitSrpUpdate(aError, *aUpdate);
|
|
||||||
aUpdate->Free();
|
// We add new `update` at the tail of the `mCompletedUpdates` list
|
||||||
|
// so that updates are processed in the order we receive the
|
||||||
|
// `HandleServiceUpdateResult()` callbacks for them. The
|
||||||
|
// completed updates are processed from `mCompletedUpdateTask`
|
||||||
|
// and `ProcessCompletedUpdates()`.
|
||||||
|
|
||||||
|
mCompletedUpdates.PushAfterTail(*update);
|
||||||
|
mCompletedUpdateTask.Post();
|
||||||
|
|
||||||
if (mOutstandingUpdates.IsEmpty())
|
if (mOutstandingUpdates.IsEmpty())
|
||||||
{
|
{
|
||||||
@@ -410,6 +411,19 @@ void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError)
|
|||||||
{
|
{
|
||||||
mOutstandingUpdatesTimer.FireAt(mOutstandingUpdates.GetTail()->GetExpireTime());
|
mOutstandingUpdatesTimer.FireAt(mOutstandingUpdates.GetTail()->GetExpireTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::ProcessCompletedUpdates(void)
|
||||||
|
{
|
||||||
|
UpdateMetadata *update;
|
||||||
|
|
||||||
|
while ((update = mCompletedUpdates.Pop()) != nullptr)
|
||||||
|
{
|
||||||
|
CommitSrpUpdate(*update);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata)
|
void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata)
|
||||||
@@ -418,11 +432,13 @@ void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &a
|
|||||||
aMessageMetadata.mTtlConfig, aMessageMetadata.mLeaseConfig);
|
aMessageMetadata.mTtlConfig, aMessageMetadata.mLeaseConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::CommitSrpUpdate(Error aError, UpdateMetadata &aUpdateMetadata)
|
void Server::CommitSrpUpdate(UpdateMetadata &aUpdateMetadata)
|
||||||
{
|
{
|
||||||
CommitSrpUpdate(aError, aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(),
|
CommitSrpUpdate(aUpdateMetadata.GetError(), aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(),
|
||||||
aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr,
|
aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr,
|
||||||
aUpdateMetadata.GetTtlConfig(), aUpdateMetadata.GetLeaseConfig());
|
aUpdateMetadata.GetTtlConfig(), aUpdateMetadata.GetLeaseConfig());
|
||||||
|
|
||||||
|
aUpdateMetadata.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::CommitSrpUpdate(Error aError,
|
void Server::CommitSrpUpdate(Error aError,
|
||||||
@@ -1663,10 +1679,22 @@ void Server::HandleLeaseTimer(void)
|
|||||||
|
|
||||||
void Server::HandleOutstandingUpdatesTimer(void)
|
void Server::HandleOutstandingUpdatesTimer(void)
|
||||||
{
|
{
|
||||||
while (!mOutstandingUpdates.IsEmpty() && mOutstandingUpdates.GetTail()->GetExpireTime() <= TimerMilli::GetNow())
|
TimeMilli now = TimerMilli::GetNow();
|
||||||
|
UpdateMetadata *update;
|
||||||
|
|
||||||
|
while ((update = mOutstandingUpdates.GetTail()) != nullptr)
|
||||||
{
|
{
|
||||||
LogInfo("Outstanding service update timeout (updateId = %lu)", ToUlong(mOutstandingUpdates.GetTail()->GetId()));
|
if (update->GetExpireTime() > now)
|
||||||
HandleServiceUpdateResult(mOutstandingUpdates.GetTail(), kErrorResponseTimeout);
|
{
|
||||||
|
mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo("Outstanding service update timeout (updateId = %lu)", ToUlong(update->GetId()));
|
||||||
|
|
||||||
|
IgnoreError(mOutstandingUpdates.Remove(*update));
|
||||||
|
update->SetError(kErrorResponseTimeout);
|
||||||
|
CommitSrpUpdate(*update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2097,6 +2125,7 @@ Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const M
|
|||||||
, mTtlConfig(aMessageMetadata.mTtlConfig)
|
, mTtlConfig(aMessageMetadata.mTtlConfig)
|
||||||
, mLeaseConfig(aMessageMetadata.mLeaseConfig)
|
, mLeaseConfig(aMessageMetadata.mLeaseConfig)
|
||||||
, mHost(aHost)
|
, mHost(aHost)
|
||||||
|
, mError(kErrorNone)
|
||||||
, mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
|
, mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
|
||||||
{
|
{
|
||||||
if (aMessageMetadata.mMessageInfo != nullptr)
|
if (aMessageMetadata.mMessageInfo != nullptr)
|
||||||
|
|||||||
@@ -912,6 +912,8 @@ private:
|
|||||||
const LeaseConfig &GetLeaseConfig(void) const { return mLeaseConfig; }
|
const LeaseConfig &GetLeaseConfig(void) const { return mLeaseConfig; }
|
||||||
Host &GetHost(void) { return mHost; }
|
Host &GetHost(void) { return mHost; }
|
||||||
const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; }
|
const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; }
|
||||||
|
Error GetError(void) const { return mError; }
|
||||||
|
void SetError(Error aError) { mError = aError; }
|
||||||
bool IsDirectRxFromClient(void) const { return mIsDirectRxFromClient; }
|
bool IsDirectRxFromClient(void) const { return mIsDirectRxFromClient; }
|
||||||
bool Matches(ServiceUpdateId aId) const { return mId == aId; }
|
bool Matches(ServiceUpdateId aId) const { return mId == aId; }
|
||||||
|
|
||||||
@@ -926,6 +928,7 @@ private:
|
|||||||
LeaseConfig mLeaseConfig; // Lease config to use when processing the message.
|
LeaseConfig mLeaseConfig; // Lease config to use when processing the message.
|
||||||
Host &mHost; // The `UpdateMetadata` has no ownership of this host.
|
Host &mHost; // The `UpdateMetadata` has no ownership of this host.
|
||||||
Ip6::MessageInfo mMessageInfo; // Valid when `mIsDirectRxFromClient` is true.
|
Ip6::MessageInfo mMessageInfo; // Valid when `mIsDirectRxFromClient` is true.
|
||||||
|
Error mError;
|
||||||
bool mIsDirectRxFromClient;
|
bool mIsDirectRxFromClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -948,7 +951,7 @@ private:
|
|||||||
|
|
||||||
void InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata);
|
void InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata);
|
||||||
void CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata);
|
void CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata);
|
||||||
void CommitSrpUpdate(Error aError, UpdateMetadata &aUpdateMetadata);
|
void CommitSrpUpdate(UpdateMetadata &aUpdateMetadata);
|
||||||
void CommitSrpUpdate(Error aError,
|
void CommitSrpUpdate(Error aError,
|
||||||
Host &aHost,
|
Host &aHost,
|
||||||
const Dns::UpdateHeader &aDnsHeader,
|
const Dns::UpdateHeader &aDnsHeader,
|
||||||
@@ -998,15 +1001,16 @@ private:
|
|||||||
void HandleLeaseTimer(void);
|
void HandleLeaseTimer(void);
|
||||||
static void HandleOutstandingUpdatesTimer(Timer &aTimer);
|
static void HandleOutstandingUpdatesTimer(Timer &aTimer);
|
||||||
void HandleOutstandingUpdatesTimer(void);
|
void HandleOutstandingUpdatesTimer(void);
|
||||||
|
void ProcessCompletedUpdates(void);
|
||||||
|
|
||||||
void HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError);
|
|
||||||
const UpdateMetadata *FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const;
|
const UpdateMetadata *FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const;
|
||||||
static const char *AddressModeToString(AddressMode aMode);
|
static const char *AddressModeToString(AddressMode aMode);
|
||||||
|
|
||||||
void UpdateResponseCounters(Dns::Header::Response aResponseCode);
|
void UpdateResponseCounters(Dns::Header::Response aResponseCode);
|
||||||
|
|
||||||
using LeaseTimer = TimerMilliIn<Server, &Server::HandleLeaseTimer>;
|
using LeaseTimer = TimerMilliIn<Server, &Server::HandleLeaseTimer>;
|
||||||
using UpdateTimer = TimerMilliIn<Server, &Server::HandleOutstandingUpdatesTimer>;
|
using UpdateTimer = TimerMilliIn<Server, &Server::HandleOutstandingUpdatesTimer>;
|
||||||
|
using CompletedUpdatesTask = TaskletIn<Server, &Server::ProcessCompletedUpdates>;
|
||||||
|
|
||||||
Ip6::Udp::Socket mSocket;
|
Ip6::Udp::Socket mSocket;
|
||||||
|
|
||||||
@@ -1022,6 +1026,8 @@ private:
|
|||||||
|
|
||||||
UpdateTimer mOutstandingUpdatesTimer;
|
UpdateTimer mOutstandingUpdatesTimer;
|
||||||
LinkedList<UpdateMetadata> mOutstandingUpdates;
|
LinkedList<UpdateMetadata> mOutstandingUpdates;
|
||||||
|
LinkedList<UpdateMetadata> mCompletedUpdates;
|
||||||
|
CompletedUpdatesTask mCompletedUpdateTask;
|
||||||
|
|
||||||
ServiceUpdateId mServiceUpdateId;
|
ServiceUpdateId mServiceUpdateId;
|
||||||
uint16_t mPort;
|
uint16_t mPort;
|
||||||
|
|||||||
@@ -294,6 +294,16 @@ void TestLinkedList(void)
|
|||||||
list.RemoveAllMatching(kBetaType, removedList);
|
list.RemoveAllMatching(kBetaType, removedList);
|
||||||
VerifyLinkedListContent(&list, &a, &b, &e, nullptr);
|
VerifyLinkedListContent(&list, &a, &b, &e, nullptr);
|
||||||
VerifyLinkedListContent(&removedList, &f, &d, &c, nullptr);
|
VerifyLinkedListContent(&removedList, &f, &d, &c, nullptr);
|
||||||
|
|
||||||
|
list.Clear();
|
||||||
|
list.PushAfterTail(a);
|
||||||
|
VerifyLinkedListContent(&list, &a, nullptr);
|
||||||
|
list.PushAfterTail(b);
|
||||||
|
VerifyLinkedListContent(&list, &a, &b, nullptr);
|
||||||
|
list.PushAfterTail(c);
|
||||||
|
VerifyLinkedListContent(&list, &a, &b, &c, nullptr);
|
||||||
|
list.PushAfterTail(d);
|
||||||
|
VerifyLinkedListContent(&list, &a, &b, &c, &d, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestOwningList(void)
|
void TestOwningList(void)
|
||||||
|
|||||||
Reference in New Issue
Block a user