blob: 7fd050c42f4436d36421c3dc5121df492e482bf8 [file]
/*
* Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes implementation of mDNS publisher.
*/
#define OTBR_LOG_TAG "MDNS"
#include "mdns/mdns.hpp"
#if OTBR_ENABLE_MDNS
#include <assert.h>
#include <algorithm>
#include <functional>
#include "common/code_utils.hpp"
#include "utils/dns_utils.hpp"
namespace otbr {
namespace Mdns {
void Publisher::PublishService(const std::string &aHostName,
const std::string &aName,
const std::string &aType,
const SubTypeList &aSubTypeList,
uint16_t aPort,
const TxtData &aTxtData,
ResultCallback &&aCallback)
{
otbrError error;
mServiceRegistrationBeginTime[std::make_pair(aName, aType)] = Clock::now();
error = PublishServiceImpl(aHostName, aName, aType, aSubTypeList, aPort, aTxtData, std::move(aCallback));
if (error != OTBR_ERROR_NONE)
{
UpdateMdnsResponseCounters(mTelemetryInfo.mServiceRegistrations, error);
}
}
void Publisher::PublishHost(const std::string &aName, const AddressList &aAddresses, ResultCallback &&aCallback)
{
otbrError error;
mHostRegistrationBeginTime[aName] = Clock::now();
error = PublishHostImpl(aName, aAddresses, std::move(aCallback));
if (error != OTBR_ERROR_NONE)
{
UpdateMdnsResponseCounters(mTelemetryInfo.mHostRegistrations, error);
}
}
void Publisher::PublishKey(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback)
{
otbrError error;
mKeyRegistrationBeginTime[aName] = Clock::now();
error = PublishKeyImpl(aName, aKeyData, std::move(aCallback));
if (error != OTBR_ERROR_NONE)
{
UpdateMdnsResponseCounters(mTelemetryInfo.mKeyRegistrations, error);
}
}
void Publisher::OnServiceResolveFailed(std::string aType, std::string aInstanceName, int32_t aErrorCode)
{
UpdateMdnsResponseCounters(mTelemetryInfo.mServiceResolutions, DnsErrorToOtbrError(aErrorCode));
UpdateServiceInstanceResolutionEmaLatency(aInstanceName, aType, DnsErrorToOtbrError(aErrorCode));
OnServiceResolveFailedImpl(aType, aInstanceName, aErrorCode);
}
void Publisher::OnHostResolveFailed(std::string aHostName, int32_t aErrorCode)
{
UpdateMdnsResponseCounters(mTelemetryInfo.mHostResolutions, DnsErrorToOtbrError(aErrorCode));
UpdateHostResolutionEmaLatency(aHostName, DnsErrorToOtbrError(aErrorCode));
OnHostResolveFailedImpl(aHostName, aErrorCode);
}
otbrError Publisher::EncodeTxtData(const TxtList &aTxtList, std::vector<uint8_t> &aTxtData)
{
otbrError error = OTBR_ERROR_NONE;
aTxtData.clear();
for (const TxtEntry &txtEntry : aTxtList)
{
size_t entryLength = txtEntry.mKey.length();
if (!txtEntry.mIsBooleanAttribute)
{
entryLength += txtEntry.mValue.size() + sizeof(uint8_t); // for `=` char.
}
VerifyOrExit(entryLength <= kMaxTextEntrySize, error = OTBR_ERROR_INVALID_ARGS);
aTxtData.push_back(static_cast<uint8_t>(entryLength));
aTxtData.insert(aTxtData.end(), txtEntry.mKey.begin(), txtEntry.mKey.end());
if (!txtEntry.mIsBooleanAttribute)
{
aTxtData.push_back('=');
aTxtData.insert(aTxtData.end(), txtEntry.mValue.begin(), txtEntry.mValue.end());
}
}
if (aTxtData.empty())
{
aTxtData.push_back(0);
}
exit:
return error;
}
otbrError Publisher::DecodeTxtData(Publisher::TxtList &aTxtList, const uint8_t *aTxtData, uint16_t aTxtLength)
{
otbrError error = OTBR_ERROR_NONE;
aTxtList.clear();
for (uint16_t r = 0; r < aTxtLength;)
{
uint16_t entrySize = aTxtData[r];
uint16_t keyStart = r + 1;
uint16_t entryEnd = keyStart + entrySize;
uint16_t keyEnd = keyStart;
VerifyOrExit(entryEnd <= aTxtLength, error = OTBR_ERROR_PARSE);
while (keyEnd < entryEnd && aTxtData[keyEnd] != '=')
{
keyEnd++;
}
if (keyEnd == entryEnd)
{
if (keyEnd > keyStart)
{
// No `=`, treat as a boolean attribute.
aTxtList.emplace_back(reinterpret_cast<const char *>(&aTxtData[keyStart]), keyEnd - keyStart);
}
}
else
{
uint16_t valStart = keyEnd + 1; // To skip over `=`
aTxtList.emplace_back(reinterpret_cast<const char *>(&aTxtData[keyStart]), keyEnd - keyStart,
&aTxtData[valStart], entryEnd - valStart);
}
r += entrySize + 1;
}
exit:
return error;
}
void Publisher::RemoveSubscriptionCallbacks(uint64_t aSubscriberId)
{
mDiscoverCallbacks.remove_if(
[aSubscriberId](const DiscoverCallback &aCallback) { return (aCallback.mId == aSubscriberId); });
}
uint64_t Publisher::AddSubscriptionCallbacks(Publisher::DiscoveredServiceInstanceCallback aInstanceCallback,
Publisher::DiscoveredHostCallback aHostCallback)
{
uint64_t id = mNextSubscriberId++;
assert(id > 0);
mDiscoverCallbacks.emplace_back(id, aInstanceCallback, aHostCallback);
return id;
}
void Publisher::OnServiceResolved(std::string aType, DiscoveredInstanceInfo aInstanceInfo)
{
bool checkToInvoke = false;
otbrLogInfo("Service %s is resolved successfully: %s %s host %s addresses %zu", aType.c_str(),
aInstanceInfo.mRemoved ? "remove" : "add", aInstanceInfo.mName.c_str(), aInstanceInfo.mHostName.c_str(),
aInstanceInfo.mAddresses.size());
if (!aInstanceInfo.mRemoved)
{
std::string addressesString;
for (const auto &address : aInstanceInfo.mAddresses)
{
addressesString += address.ToString() + ",";
}
if (addressesString.size())
{
addressesString.pop_back();
}
otbrLogInfo("addresses: [ %s ]", addressesString.c_str());
}
DnsUtils::CheckServiceNameSanity(aType);
assert(aInstanceInfo.mNetifIndex > 0);
if (!aInstanceInfo.mRemoved)
{
DnsUtils::CheckHostnameSanity(aInstanceInfo.mHostName);
}
UpdateMdnsResponseCounters(mTelemetryInfo.mServiceResolutions, OTBR_ERROR_NONE);
UpdateServiceInstanceResolutionEmaLatency(aInstanceInfo.mName, aType, OTBR_ERROR_NONE);
// The `mDiscoverCallbacks` list can get updated as the callbacks
// are invoked. We first mark `mShouldInvoke` on all non-null
// service callbacks. We clear it before invoking the callback
// and restart the iteration over the `mDiscoverCallbacks` list
// to find the next one to signal, since the list may have changed.
for (DiscoverCallback &callback : mDiscoverCallbacks)
{
if (callback.mServiceCallback != nullptr)
{
callback.mShouldInvoke = true;
checkToInvoke = true;
}
}
while (checkToInvoke)
{
checkToInvoke = false;
for (DiscoverCallback &callback : mDiscoverCallbacks)
{
if (callback.mShouldInvoke)
{
callback.mShouldInvoke = false;
checkToInvoke = true;
callback.mServiceCallback(aType, aInstanceInfo);
break;
}
}
}
}
void Publisher::OnServiceRemoved(uint32_t aNetifIndex, std::string aType, std::string aInstanceName)
{
DiscoveredInstanceInfo instanceInfo;
otbrLogInfo("Service %s.%s is removed from netif %u.", aInstanceName.c_str(), aType.c_str(), aNetifIndex);
instanceInfo.mRemoved = true;
instanceInfo.mNetifIndex = aNetifIndex;
instanceInfo.mName = aInstanceName;
OnServiceResolved(aType, instanceInfo);
}
void Publisher::OnHostResolved(std::string aHostName, Publisher::DiscoveredHostInfo aHostInfo)
{
bool checkToInvoke = false;
otbrLogInfo("Host %s is resolved successfully: host %s addresses %zu ttl %u", aHostName.c_str(),
aHostInfo.mHostName.c_str(), aHostInfo.mAddresses.size(), aHostInfo.mTtl);
if (!aHostInfo.mHostName.empty())
{
DnsUtils::CheckHostnameSanity(aHostInfo.mHostName);
}
UpdateMdnsResponseCounters(mTelemetryInfo.mHostResolutions, OTBR_ERROR_NONE);
UpdateHostResolutionEmaLatency(aHostName, OTBR_ERROR_NONE);
// The `mDiscoverCallbacks` list can get updated as the callbacks
// are invoked. We first mark `mShouldInvoke` on all non-null
// host callbacks. We clear it before invoking the callback
// and restart the iteration over the `mDiscoverCallbacks` list
// to find the next one to signal, since the list may have changed.
for (DiscoverCallback &callback : mDiscoverCallbacks)
{
if (callback.mHostCallback != nullptr)
{
callback.mShouldInvoke = true;
checkToInvoke = true;
}
}
while (checkToInvoke)
{
checkToInvoke = false;
for (DiscoverCallback &callback : mDiscoverCallbacks)
{
if (callback.mShouldInvoke)
{
callback.mShouldInvoke = false;
checkToInvoke = true;
callback.mHostCallback(aHostName, aHostInfo);
break;
}
}
}
}
Publisher::SubTypeList Publisher::SortSubTypeList(SubTypeList aSubTypeList)
{
std::sort(aSubTypeList.begin(), aSubTypeList.end());
return aSubTypeList;
}
Publisher::AddressList Publisher::SortAddressList(AddressList aAddressList)
{
std::sort(aAddressList.begin(), aAddressList.end());
return aAddressList;
}
std::string Publisher::MakeFullServiceName(const std::string &aName, const std::string &aType)
{
return aName + "." + aType + ".local";
}
std::string Publisher::MakeFullName(const std::string &aName)
{
return aName + ".local";
}
void Publisher::AddServiceRegistration(ServiceRegistrationPtr &&aServiceReg)
{
mServiceRegistrations.emplace(MakeFullServiceName(aServiceReg->mName, aServiceReg->mType), std::move(aServiceReg));
}
void Publisher::RemoveServiceRegistration(const std::string &aName, const std::string &aType, otbrError aError)
{
auto it = mServiceRegistrations.find(MakeFullServiceName(aName, aType));
ServiceRegistrationPtr serviceReg;
otbrLogInfo("Removing service %s.%s", aName.c_str(), aType.c_str());
VerifyOrExit(it != mServiceRegistrations.end());
// Keep the ServiceRegistration around before calling `Complete`
// to invoke the callback. This is for avoiding invalid access
// to the ServiceRegistration when it's freed from the callback.
serviceReg = std::move(it->second);
mServiceRegistrations.erase(it);
serviceReg->Complete(aError);
exit:
return;
}
Publisher::ServiceRegistration *Publisher::FindServiceRegistration(const std::string &aName, const std::string &aType)
{
auto it = mServiceRegistrations.find(MakeFullServiceName(aName, aType));
return it != mServiceRegistrations.end() ? it->second.get() : nullptr;
}
Publisher::ServiceRegistration *Publisher::FindServiceRegistration(const std::string &aNameAndType)
{
auto it = mServiceRegistrations.find(MakeFullName(aNameAndType));
return it != mServiceRegistrations.end() ? it->second.get() : nullptr;
}
Publisher::ResultCallback Publisher::HandleDuplicateServiceRegistration(const std::string &aHostName,
const std::string &aName,
const std::string &aType,
const SubTypeList &aSubTypeList,
uint16_t aPort,
const TxtData &aTxtData,
ResultCallback &&aCallback)
{
ServiceRegistration *serviceReg = FindServiceRegistration(aName, aType);
VerifyOrExit(serviceReg != nullptr);
if (serviceReg->IsOutdated(aHostName, aName, aType, aSubTypeList, aPort, aTxtData))
{
otbrLogInfo("Removing existing service %s.%s: outdated", aName.c_str(), aType.c_str());
RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED);
}
else if (serviceReg->IsCompleted())
{
// Returns success if the same service has already been
// registered with exactly the same parameters.
std::move(aCallback)(OTBR_ERROR_NONE);
}
else
{
// If the same service is being registered with the same parameters,
// let's join the waiting queue for the result.
serviceReg->mCallback = std::bind(
[](std::shared_ptr<ResultCallback> aExistingCallback, std::shared_ptr<ResultCallback> aNewCallback,
otbrError aError) {
std::move (*aExistingCallback)(aError);
std::move (*aNewCallback)(aError);
},
std::make_shared<ResultCallback>(std::move(serviceReg->mCallback)),
std::make_shared<ResultCallback>(std::move(aCallback)), std::placeholders::_1);
}
exit:
return std::move(aCallback);
}
Publisher::ResultCallback Publisher::HandleDuplicateHostRegistration(const std::string &aName,
const AddressList &aAddresses,
ResultCallback &&aCallback)
{
HostRegistration *hostReg = FindHostRegistration(aName);
VerifyOrExit(hostReg != nullptr);
if (hostReg->IsOutdated(aName, aAddresses))
{
otbrLogInfo("Removing existing host %s: outdated", aName.c_str());
RemoveHostRegistration(hostReg->mName, OTBR_ERROR_ABORTED);
}
else if (hostReg->IsCompleted())
{
// Returns success if the same service has already been
// registered with exactly the same parameters.
std::move(aCallback)(OTBR_ERROR_NONE);
}
else
{
// If the same service is being registered with the same parameters,
// let's join the waiting queue for the result.
hostReg->mCallback = std::bind(
[](std::shared_ptr<ResultCallback> aExistingCallback, std::shared_ptr<ResultCallback> aNewCallback,
otbrError aError) {
std::move (*aExistingCallback)(aError);
std::move (*aNewCallback)(aError);
},
std::make_shared<ResultCallback>(std::move(hostReg->mCallback)),
std::make_shared<ResultCallback>(std::move(aCallback)), std::placeholders::_1);
}
exit:
return std::move(aCallback);
}
void Publisher::AddHostRegistration(HostRegistrationPtr &&aHostReg)
{
mHostRegistrations.emplace(MakeFullHostName(aHostReg->mName), std::move(aHostReg));
}
void Publisher::RemoveHostRegistration(const std::string &aName, otbrError aError)
{
auto it = mHostRegistrations.find(MakeFullHostName(aName));
HostRegistrationPtr hostReg;
otbrLogInfo("Removing host %s", aName.c_str());
VerifyOrExit(it != mHostRegistrations.end());
// Keep the HostRegistration around before calling `Complete`
// to invoke the callback. This is for avoiding invalid access
// to the HostRegistration when it's freed from the callback.
hostReg = std::move(it->second);
mHostRegistrations.erase(it);
hostReg->Complete(aError);
otbrLogInfo("Removed host %s", aName.c_str());
exit:
return;
}
Publisher::HostRegistration *Publisher::FindHostRegistration(const std::string &aName)
{
auto it = mHostRegistrations.find(MakeFullHostName(aName));
return it != mHostRegistrations.end() ? it->second.get() : nullptr;
}
Publisher::ResultCallback Publisher::HandleDuplicateKeyRegistration(const std::string &aName,
const KeyData &aKeyData,
ResultCallback &&aCallback)
{
KeyRegistration *keyReg = FindKeyRegistration(aName);
VerifyOrExit(keyReg != nullptr);
if (keyReg->IsOutdated(aName, aKeyData))
{
otbrLogInfo("Removing existing key %s: outdated", aName.c_str());
RemoveKeyRegistration(keyReg->mName, OTBR_ERROR_ABORTED);
}
else if (keyReg->IsCompleted())
{
// Returns success if the same key has already been
// registered with exactly the same parameters.
std::move(aCallback)(OTBR_ERROR_NONE);
}
else
{
// If the same key is being registered with the same parameters,
// let's join the waiting queue for the result.
keyReg->mCallback = std::bind(
[](std::shared_ptr<ResultCallback> aExistingCallback, std::shared_ptr<ResultCallback> aNewCallback,
otbrError aError) {
std::move (*aExistingCallback)(aError);
std::move (*aNewCallback)(aError);
},
std::make_shared<ResultCallback>(std::move(keyReg->mCallback)),
std::make_shared<ResultCallback>(std::move(aCallback)), std::placeholders::_1);
}
exit:
return std::move(aCallback);
}
void Publisher::AddKeyRegistration(KeyRegistrationPtr &&aKeyReg)
{
mKeyRegistrations.emplace(MakeFullKeyName(aKeyReg->mName), std::move(aKeyReg));
}
void Publisher::RemoveKeyRegistration(const std::string &aName, otbrError aError)
{
auto it = mKeyRegistrations.find(MakeFullKeyName(aName));
KeyRegistrationPtr keyReg;
otbrLogInfo("Removing key %s", aName.c_str());
VerifyOrExit(it != mKeyRegistrations.end());
// Keep the KeyRegistration around before calling `Complete`
// to invoke the callback. This is for avoiding invalid access
// to the KeyRegistration when it's freed from the callback.
keyReg = std::move(it->second);
mKeyRegistrations.erase(it);
keyReg->Complete(aError);
otbrLogInfo("Removed key %s", aName.c_str());
exit:
return;
}
Publisher::KeyRegistration *Publisher::FindKeyRegistration(const std::string &aName)
{
auto it = mKeyRegistrations.find(MakeFullKeyName(aName));
return it != mKeyRegistrations.end() ? it->second.get() : nullptr;
}
Publisher::KeyRegistration *Publisher::FindKeyRegistration(const std::string &aName, const std::string &aType)
{
auto it = mKeyRegistrations.find(MakeFullServiceName(aName, aType));
return it != mKeyRegistrations.end() ? it->second.get() : nullptr;
}
Publisher::Registration::~Registration(void)
{
TriggerCompleteCallback(OTBR_ERROR_ABORTED);
}
bool Publisher::ServiceRegistration::IsOutdated(const std::string &aHostName,
const std::string &aName,
const std::string &aType,
const SubTypeList &aSubTypeList,
uint16_t aPort,
const TxtData &aTxtData) const
{
return !(mHostName == aHostName && mName == aName && mType == aType && mSubTypeList == aSubTypeList &&
mPort == aPort && mTxtData == aTxtData);
}
void Publisher::ServiceRegistration::Complete(otbrError aError)
{
OnComplete(aError);
Registration::TriggerCompleteCallback(aError);
}
void Publisher::ServiceRegistration::OnComplete(otbrError aError)
{
if (!IsCompleted())
{
mPublisher->UpdateMdnsResponseCounters(mPublisher->mTelemetryInfo.mServiceRegistrations, aError);
mPublisher->UpdateServiceRegistrationEmaLatency(mName, mType, aError);
}
}
bool Publisher::HostRegistration::IsOutdated(const std::string &aName, const AddressList &aAddresses) const
{
return !(mName == aName && mAddresses == aAddresses);
}
void Publisher::HostRegistration::Complete(otbrError aError)
{
OnComplete(aError);
Registration::TriggerCompleteCallback(aError);
}
void Publisher::HostRegistration::OnComplete(otbrError aError)
{
if (!IsCompleted())
{
mPublisher->UpdateMdnsResponseCounters(mPublisher->mTelemetryInfo.mHostRegistrations, aError);
mPublisher->UpdateHostRegistrationEmaLatency(mName, aError);
}
}
bool Publisher::KeyRegistration::IsOutdated(const std::string &aName, const KeyData &aKeyData) const
{
return !(mName == aName && mKeyData == aKeyData);
}
void Publisher::KeyRegistration::Complete(otbrError aError)
{
OnComplete(aError);
Registration::TriggerCompleteCallback(aError);
}
void Publisher::KeyRegistration::OnComplete(otbrError aError)
{
if (!IsCompleted())
{
mPublisher->UpdateMdnsResponseCounters(mPublisher->mTelemetryInfo.mKeyRegistrations, aError);
mPublisher->UpdateKeyRegistrationEmaLatency(mName, aError);
}
}
void Publisher::UpdateMdnsResponseCounters(otbr::MdnsResponseCounters &aCounters, otbrError aError)
{
switch (aError)
{
case OTBR_ERROR_NONE:
++aCounters.mSuccess;
break;
case OTBR_ERROR_NOT_FOUND:
++aCounters.mNotFound;
break;
case OTBR_ERROR_INVALID_ARGS:
++aCounters.mInvalidArgs;
break;
case OTBR_ERROR_DUPLICATED:
++aCounters.mDuplicated;
break;
case OTBR_ERROR_NOT_IMPLEMENTED:
++aCounters.mNotImplemented;
break;
case OTBR_ERROR_ABORTED:
++aCounters.mAborted;
break;
case OTBR_ERROR_INVALID_STATE:
++aCounters.mInvalidState;
break;
case OTBR_ERROR_MDNS:
default:
++aCounters.mUnknownError;
break;
}
}
void Publisher::UpdateEmaLatency(uint32_t &aEmaLatency, uint32_t aLatency, otbrError aError)
{
VerifyOrExit(aError != OTBR_ERROR_ABORTED);
if (!aEmaLatency)
{
aEmaLatency = aLatency;
}
else
{
aEmaLatency =
(aLatency * MdnsTelemetryInfo::kEmaFactorNumerator +
aEmaLatency * (MdnsTelemetryInfo::kEmaFactorDenominator - MdnsTelemetryInfo::kEmaFactorNumerator)) /
MdnsTelemetryInfo::kEmaFactorDenominator;
}
exit:
return;
}
void Publisher::UpdateServiceRegistrationEmaLatency(const std::string &aInstanceName,
const std::string &aType,
otbrError aError)
{
auto it = mServiceRegistrationBeginTime.find(std::make_pair(aInstanceName, aType));
if (it != mServiceRegistrationBeginTime.end())
{
uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
UpdateEmaLatency(mTelemetryInfo.mServiceRegistrationEmaLatency, latency, aError);
mServiceRegistrationBeginTime.erase(it);
}
}
void Publisher::UpdateHostRegistrationEmaLatency(const std::string &aHostName, otbrError aError)
{
auto it = mHostRegistrationBeginTime.find(aHostName);
if (it != mHostRegistrationBeginTime.end())
{
uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
UpdateEmaLatency(mTelemetryInfo.mHostRegistrationEmaLatency, latency, aError);
mHostRegistrationBeginTime.erase(it);
}
}
void Publisher::UpdateKeyRegistrationEmaLatency(const std::string &aKeyName, otbrError aError)
{
auto it = mKeyRegistrationBeginTime.find(aKeyName);
if (it != mKeyRegistrationBeginTime.end())
{
uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
UpdateEmaLatency(mTelemetryInfo.mKeyRegistrationEmaLatency, latency, aError);
mKeyRegistrationBeginTime.erase(it);
}
}
void Publisher::UpdateServiceInstanceResolutionEmaLatency(const std::string &aInstanceName,
const std::string &aType,
otbrError aError)
{
auto it = mServiceInstanceResolutionBeginTime.find(std::make_pair(aInstanceName, aType));
if (it != mServiceInstanceResolutionBeginTime.end())
{
uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
UpdateEmaLatency(mTelemetryInfo.mServiceResolutionEmaLatency, latency, aError);
mServiceInstanceResolutionBeginTime.erase(it);
}
}
void Publisher::UpdateHostResolutionEmaLatency(const std::string &aHostName, otbrError aError)
{
auto it = mHostResolutionBeginTime.find(aHostName);
if (it != mHostResolutionBeginTime.end())
{
uint32_t latency = std::chrono::duration_cast<Milliseconds>(Clock::now() - it->second).count();
UpdateEmaLatency(mTelemetryInfo.mHostResolutionEmaLatency, latency, aError);
mHostResolutionBeginTime.erase(it);
}
}
void Publisher::AddAddress(AddressList &aAddressList, const Ip6Address &aAddress)
{
aAddressList.push_back(aAddress);
}
void Publisher::RemoveAddress(AddressList &aAddressList, const Ip6Address &aAddress)
{
auto it = std::find(aAddressList.begin(), aAddressList.end(), aAddress);
if (it != aAddressList.end())
{
aAddressList.erase(it);
}
}
void StateSubject::AddObserver(StateObserver &aObserver)
{
mObservers.push_back(&aObserver);
}
void StateSubject::UpdateState(Publisher::State aState)
{
for (StateObserver *observer : mObservers)
{
observer->HandleMdnsState(aState);
}
}
void StateSubject::Clear(void)
{
mObservers.clear();
}
} // namespace Mdns
} // namespace otbr
#endif // OTBR_ENABLE_MDNS