mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 19:57:46 +00:00
[mdns] add APIs to iterate over registered host/service/key entries (#9954)
This commit is contained in:
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (406)
|
||||
#define OPENTHREAD_API_VERSION (407)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
+112
-10
@@ -133,6 +133,24 @@ typedef otPlatDnssdService otMdnsService;
|
||||
*/
|
||||
typedef otPlatDnssdKey otMdnsKey;
|
||||
|
||||
/**
|
||||
* Represents an mDNS entry iterator.
|
||||
*
|
||||
*/
|
||||
typedef struct otMdnsIterator otMdnsIterator;
|
||||
|
||||
/**
|
||||
* Represents a host/service/key entry state.
|
||||
*
|
||||
*/
|
||||
typedef enum otMdnsEntryState
|
||||
{
|
||||
OT_MDNS_ENTRY_STATE_PROBING, ///< Probing to claim the name.
|
||||
OT_MDNS_ENTRY_STATE_REGISTERED, ///< Entry is successfully registered.
|
||||
OT_MDNS_ENTRY_STATE_CONFLICT, ///< Name conflict was detected.
|
||||
OT_MDNS_ENTRY_STATE_REMOVING, ///< Entry is being removed (sending "goodbye" announcements).
|
||||
} otMdnsEntryState;
|
||||
|
||||
/**
|
||||
* Enables or disables the mDNS module.
|
||||
*
|
||||
@@ -335,10 +353,11 @@ otError otMdnsUnregisterService(otInstance *aInstance, const otMdnsService *aSer
|
||||
*
|
||||
* The fields in @p aKey follow these rules:
|
||||
*
|
||||
* - If the key is associated with a host entry, `mName` specifies the host name and `mServcieType` MUST be NULL.
|
||||
* - If the key is associated with a service entry, `mName` specifies the service instance label (always treated as
|
||||
* a single label) and `mServiceType` specifies the service type (e.g., "_tst._udp"). In this case the DNS name for
|
||||
* key record is `<mName>.<mServiceTye>`.
|
||||
* - If the key is associated with a host entry, the `mName` field specifies the host name and the `mServiceType` MUST
|
||||
* be NULL.
|
||||
* - If the key is associated with a service entry, the `mName` filed specifies the service instance label (always
|
||||
* treated as a single label) and the `mServiceType` filed specifies the service type (e.g., "_tst._udp"). In this
|
||||
* case the DNS name for key record is `<mName>.<mServiceTye>`.
|
||||
* - The `mKeyData` field contains the key record's data with `mKeyDataLength` as its length in byes.
|
||||
* - The `mTtl` specifies the TTL if non-zero. If zero, the mDNS module will use the default TTL of 120 seconds.
|
||||
* - Other fields in @p aKey structure are ignored in an `otMdnsRegisterKey()` call.
|
||||
@@ -368,10 +387,11 @@ otError otMdnsRegisterKey(otInstance *aInstance,
|
||||
*
|
||||
* The fields in @p aKey follow these rules:
|
||||
*
|
||||
* - If the key is associated with a host entry, `mName` specifies the host name and `mServcieType` MUST be NULL.
|
||||
* - If the key is associated with a service entry, `mName` specifies the service instance label (always treated as
|
||||
* a single label) and `mServiceType` specifies the service type (e.g., "_tst._udp"). In this case the DNS name for
|
||||
* key record is `<mName>.<mServiceTye>`.
|
||||
* - If the key is associated with a host entry, the `mName` field specifies the host name and the `mServiceType` MUST
|
||||
* be NULL.
|
||||
* - If the key is associated with a service entry, the `mName` filed specifies the service instance label (always
|
||||
* treated as a single label) and the `mServiceType` filed specifies the service type (e.g., "_tst._udp"). In this
|
||||
* case the DNS name for key record is `<mName>.<mServiceTye>`.
|
||||
* - Other fields in @p aKey structure are ignored in an `otMdnsUnregisterKey()` call.
|
||||
*
|
||||
* If there is no previously registered key with the same name, no action is performed.
|
||||
@@ -388,6 +408,88 @@ otError otMdnsRegisterKey(otInstance *aInstance,
|
||||
*/
|
||||
otError otMdnsUnregisterKey(otInstance *aInstance, const otMdnsKey *aKey);
|
||||
|
||||
/**
|
||||
* Allocates a new iterator.
|
||||
*
|
||||
* An allocated iterator must be freed by the caller using `otMdnsFreeIterator()`.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*
|
||||
* @returns A pointer to the allocated iterator, or `NULL` if it fails to allocate.
|
||||
*
|
||||
*/
|
||||
otMdnsIterator *otMdnsAllocateIterator(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Frees a previously allocated iterator.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aIterator The iterator to free.
|
||||
*
|
||||
*/
|
||||
void otMdnsFreeIterator(otInstance *aInstance, otMdnsIterator *aIterator);
|
||||
|
||||
/**
|
||||
* Iterates over registered host entries.
|
||||
*
|
||||
* On success, @p aHost is populated with information about the next host. Pointers within the `otMdnsHost` structure
|
||||
* (like `mName`) remain valid until the next call to any OpenThread stack's public or platform API/callback.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aIterator Pointer to the iterator.
|
||||
* @param[out] aHost Pointer to an `otMdnsHost` to return the information about the next host entry.
|
||||
* @param[out] aState Pointer to an `otMdnsEntryState` to return the entry state.
|
||||
*
|
||||
* @retval OT_ERROR_NONE @p aHost, @p aState, & @p aIterator are updated successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND Reached the end of the list.
|
||||
* @retval OT_ERROR_INVALID_ARG @p aIterator is not valid.
|
||||
*
|
||||
*/
|
||||
otError otMdnsGetNextHost(otInstance *aInstance,
|
||||
otMdnsIterator *aIterator,
|
||||
otMdnsHost *aHost,
|
||||
otMdnsEntryState *aState);
|
||||
|
||||
/**
|
||||
* Iterates over registered service entries.
|
||||
*
|
||||
* On success, @p aService is populated with information about the next service . Pointers within the `otMdnsService`
|
||||
* structure (like `mServiceType`, `mSubTypeLabels`) remain valid until the next call to any OpenThread stack's public
|
||||
* or platform API/callback.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aIterator Pointer to the iterator to use.
|
||||
* @param[out] aService Pointer to an `otMdnsService` to return the information about the next service entry.
|
||||
* @param[out] aState Pointer to an `otMdnsEntryState` to return the entry state.
|
||||
*
|
||||
* @retval OT_ERROR_NONE @p aService, @p aState, & @p aIterator are updated successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND Reached the end of the list.
|
||||
* @retval OT_ERROR_INVALID_ARG @p aIterator is not valid.
|
||||
*
|
||||
*/
|
||||
otError otMdnsGetNextService(otInstance *aInstance,
|
||||
otMdnsIterator *aIterator,
|
||||
otMdnsService *aService,
|
||||
otMdnsEntryState *aState);
|
||||
|
||||
/**
|
||||
* Iterates over registered key entries.
|
||||
*
|
||||
* On success, @p aKey is populated with information about the next key. Pointers within the `otMdnsKey` structure
|
||||
* (like `mName`) remain valid until the next call to any OpenThread stack's public or platform API/callback.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aIterator Pointer to the iterator to use.
|
||||
* @param[out] aKey Pointer to an `otMdnsKey` to return the information about the next key entry.
|
||||
* @param[out] aState Pointer to an `otMdnsEntryState` to return the entry state.
|
||||
*
|
||||
* @retval OT_ERROR_NONE @p aKey, @p aState, & @p aIterator are updated successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND Reached the end of the list.
|
||||
* @retval OT_ERROR_INVALID_ARG Iterator is not valid.
|
||||
*
|
||||
*/
|
||||
otError otMdnsGetNextKey(otInstance *aInstance, otMdnsIterator *aIterator, otMdnsKey *aKey, otMdnsEntryState *aState);
|
||||
|
||||
typedef struct otMdnsBrowseResult otMdnsBrowseResult;
|
||||
typedef struct otMdnsSrvResult otMdnsSrvResult;
|
||||
typedef struct otMdnsTxtResult otMdnsTxtResult;
|
||||
@@ -661,7 +763,7 @@ otError otMdnsStopTxtResolver(otInstance *aInstance, const otMdnsTxtResolver *aR
|
||||
*
|
||||
* Initiates a continuous IPv6 address resolver for the specified host name in @p aResolver.
|
||||
*
|
||||
* Discovered addresses are reported through the `mCallback` function in @ p aResolver. The callback is invoked
|
||||
* Discovered addresses are reported through the `mCallback` function in @p aResolver. The callback is invoked
|
||||
* whenever addresses are added or removed, providing an updated list. If all addresses are removed, the callback is
|
||||
* invoked with an empty list (`mAddresses` will be NULL, and `mAddressesLength` will be zero).
|
||||
*
|
||||
@@ -700,7 +802,7 @@ otError otMdnsStopIp6AddressResolver(otInstance *aInstance, const otMdnsAddressR
|
||||
*
|
||||
* Initiates a continuous IPv4 address resolver for the specified host name in @p aResolver.
|
||||
*
|
||||
* Discovered addresses are reported through the `mCallback` function in @ p aResolver. The IPv4 addresses are
|
||||
* Discovered addresses are reported through the `mCallback` function in @p aResolver. The IPv4 addresses are
|
||||
* represented using the IPv4-mapped IPv6 address format in `mAddresses` array. The callback is invoked whenever
|
||||
* addresses are added or removed, providing an updated list. If all addresses are removed, the callback is invoked
|
||||
* with an empty list (`mAddresses` will be NULL, and `mAddressesLength` will be zero).
|
||||
|
||||
+138
-3
@@ -148,6 +148,29 @@ void Mdns::OutputKey(const otMdnsKey &aKey)
|
||||
OutputLine(kIndentSize, "ttl: %lu", ToUlong(aKey.mTtl));
|
||||
}
|
||||
|
||||
void Mdns::OutputState(otMdnsEntryState aState)
|
||||
{
|
||||
const char *stateString = "";
|
||||
|
||||
switch (aState)
|
||||
{
|
||||
case OT_MDNS_ENTRY_STATE_PROBING:
|
||||
stateString = "probing";
|
||||
break;
|
||||
case OT_MDNS_ENTRY_STATE_REGISTERED:
|
||||
stateString = "registered";
|
||||
break;
|
||||
case OT_MDNS_ENTRY_STATE_CONFLICT:
|
||||
stateString = "conflict";
|
||||
break;
|
||||
case OT_MDNS_ENTRY_STATE_REMOVING:
|
||||
stateString = "removing";
|
||||
break;
|
||||
}
|
||||
|
||||
OutputLine(kIndentSize, "state: %s", stateString);
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("register")>(Arg aArgs[])
|
||||
{
|
||||
// mdns [async] [host|service|key] <entry specific args>
|
||||
@@ -458,6 +481,117 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("hosts")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otMdnsIterator *iterator = nullptr;
|
||||
otMdnsHost host;
|
||||
otMdnsEntryState state;
|
||||
|
||||
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
iterator = otMdnsAllocateIterator(GetInstancePtr());
|
||||
VerifyOrExit(iterator != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
while (true)
|
||||
{
|
||||
error = otMdnsGetNextHost(GetInstancePtr(), iterator, &host, &state);
|
||||
|
||||
if (error == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
error = OT_ERROR_NONE;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
SuccessOrExit(error);
|
||||
|
||||
OutputHost(host);
|
||||
OutputState(state);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (iterator != nullptr)
|
||||
{
|
||||
otMdnsFreeIterator(GetInstancePtr(), iterator);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("services")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otMdnsIterator *iterator = nullptr;
|
||||
otMdnsService service;
|
||||
otMdnsEntryState state;
|
||||
|
||||
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
iterator = otMdnsAllocateIterator(GetInstancePtr());
|
||||
VerifyOrExit(iterator != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
while (true)
|
||||
{
|
||||
error = otMdnsGetNextService(GetInstancePtr(), iterator, &service, &state);
|
||||
|
||||
if (error == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
error = OT_ERROR_NONE;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
SuccessOrExit(error);
|
||||
|
||||
OutputService(service);
|
||||
OutputState(state);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (iterator != nullptr)
|
||||
{
|
||||
otMdnsFreeIterator(GetInstancePtr(), iterator);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("keys")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otMdnsIterator *iterator = nullptr;
|
||||
otMdnsKey key;
|
||||
otMdnsEntryState state;
|
||||
|
||||
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
iterator = otMdnsAllocateIterator(GetInstancePtr());
|
||||
VerifyOrExit(iterator != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
while (true)
|
||||
{
|
||||
error = otMdnsGetNextKey(GetInstancePtr(), iterator, &key, &state);
|
||||
|
||||
if (error == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
error = OT_ERROR_NONE;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
SuccessOrExit(error);
|
||||
|
||||
OutputKey(key);
|
||||
OutputState(state);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (iterator != nullptr)
|
||||
{
|
||||
otMdnsFreeIterator(GetInstancePtr(), iterator);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Mdns::ParseStartOrStop(const Arg &aArg, bool &aIsStart)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
@@ -743,9 +877,10 @@ otError Mdns::Process(Arg aArgs[])
|
||||
}
|
||||
|
||||
static constexpr Command kCommands[] = {
|
||||
CmdEntry("browser"), CmdEntry("disable"), CmdEntry("enable"), CmdEntry("ip4resolver"),
|
||||
CmdEntry("ip6resolver"), CmdEntry("register"), CmdEntry("srvresolver"), CmdEntry("state"),
|
||||
CmdEntry("txtresolver"), CmdEntry("unicastquestion"), CmdEntry("unregister"),
|
||||
CmdEntry("browser"), CmdEntry("disable"), CmdEntry("enable"), CmdEntry("hosts"),
|
||||
CmdEntry("ip4resolver"), CmdEntry("ip6resolver"), CmdEntry("keys"), CmdEntry("register"),
|
||||
CmdEntry("services"), CmdEntry("srvresolver"), CmdEntry("state"), CmdEntry("txtresolver"),
|
||||
CmdEntry("unicastquestion"), CmdEntry("unregister"),
|
||||
};
|
||||
|
||||
#undef CmdEntry
|
||||
|
||||
@@ -110,6 +110,7 @@ private:
|
||||
void OutputHost(const otMdnsHost &aHost);
|
||||
void OutputService(const otMdnsService &aService);
|
||||
void OutputKey(const otMdnsKey &aKey);
|
||||
void OutputState(otMdnsEntryState aState);
|
||||
otError ProcessRegisterHost(Arg aArgs[]);
|
||||
otError ProcessRegisterService(Arg aArgs[]);
|
||||
otError ProcessRegisterKey(Arg aArgs[]);
|
||||
|
||||
@@ -115,6 +115,48 @@ otError otMdnsUnregisterKey(otInstance *aInstance, const otMdnsKey *aKey)
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().UnregisterKey(*aKey);
|
||||
}
|
||||
|
||||
otMdnsIterator *otMdnsAllocateIterator(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().AllocateIterator();
|
||||
}
|
||||
|
||||
void otMdnsFreeIterator(otInstance *aInstance, otMdnsIterator *aIterator)
|
||||
{
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
|
||||
AsCoreType(aInstance).Get<Dns::Multicast::Core>().FreeIterator(*aIterator);
|
||||
}
|
||||
|
||||
otError otMdnsGetNextHost(otInstance *aInstance, otMdnsIterator *aIterator, otMdnsHost *aHost, otMdnsEntryState *aState)
|
||||
{
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
AssertPointerIsNotNull(aHost);
|
||||
AssertPointerIsNotNull(aState);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().GetNextHost(*aIterator, *aHost, *aState);
|
||||
}
|
||||
|
||||
otError otMdnsGetNextService(otInstance *aInstance,
|
||||
otMdnsIterator *aIterator,
|
||||
otMdnsService *aService,
|
||||
otMdnsEntryState *aState)
|
||||
{
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
AssertPointerIsNotNull(aService);
|
||||
AssertPointerIsNotNull(aState);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().GetNextService(*aIterator, *aService, *aState);
|
||||
}
|
||||
|
||||
otError otMdnsGetNextKey(otInstance *aInstance, otMdnsIterator *aIterator, otMdnsKey *aKey, otMdnsEntryState *aState)
|
||||
{
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
AssertPointerIsNotNull(aKey);
|
||||
AssertPointerIsNotNull(aState);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().GetNextKey(*aIterator, *aKey, *aState);
|
||||
}
|
||||
|
||||
otError otMdnsStartBrowser(otInstance *aInstance, const otMdnsBrowser *aBroswer)
|
||||
{
|
||||
AssertPointerIsNotNull(aBroswer);
|
||||
|
||||
+214
-6
@@ -201,6 +201,25 @@ Error Core::UnregisterKey(const Key &aKey)
|
||||
return IsKeyForService(aKey) ? Unregister<ServiceEntry>(aKey) : Unregister<HostEntry>(aKey);
|
||||
}
|
||||
|
||||
Core::Iterator *Core::AllocateIterator(void) { return EntryIterator::Allocate(GetInstance()); }
|
||||
|
||||
void Core::FreeIterator(Iterator &aIterator) { static_cast<EntryIterator &>(aIterator).Free(); }
|
||||
|
||||
Error Core::GetNextHost(Iterator &aIterator, Host &aHost, EntryState &aState) const
|
||||
{
|
||||
return static_cast<EntryIterator &>(aIterator).GetNextHost(aHost, aState);
|
||||
}
|
||||
|
||||
Error Core::GetNextService(Iterator &aIterator, Service &aService, EntryState &aState) const
|
||||
{
|
||||
return static_cast<EntryIterator &>(aIterator).GetNextService(aService, aState);
|
||||
}
|
||||
|
||||
Error Core::GetNextKey(Iterator &aIterator, Key &aKey, EntryState &aState) const
|
||||
{
|
||||
return static_cast<EntryIterator &>(aIterator).GetNextKey(aKey, aState);
|
||||
}
|
||||
|
||||
void Core::InvokeConflictCallback(const char *aName, const char *aServiceType)
|
||||
{
|
||||
if (mConflictCallback != nullptr)
|
||||
@@ -1256,6 +1275,23 @@ void Core::Entry::AppendNsecRecordTo(TxMessage &aTxMessage,
|
||||
mAppendedNsec = true;
|
||||
}
|
||||
|
||||
Error Core::Entry::CopyKeyInfoTo(Key &aKey, EntryState &aState) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(mKeyRecord.IsPresent(), error = kErrorNotFound);
|
||||
|
||||
aKey.mKeyData = mKeyData.GetBytes();
|
||||
aKey.mKeyDataLength = mKeyData.GetLength();
|
||||
aKey.mClass = ResourceRecord::kClassInternet;
|
||||
aKey.mTtl = mKeyRecord.GetTtl();
|
||||
aKey.mInfraIfIndex = Get<Core>().mInfraIfIndex;
|
||||
aState = static_cast<EntryState>(GetState());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::HostEntry
|
||||
|
||||
@@ -1584,6 +1620,36 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
Error Core::HostEntry::CopyInfoTo(Host &aHost, EntryState &aState) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(mAddrRecord.IsPresent(), error = kErrorNotFound);
|
||||
|
||||
aHost.mHostName = mName.AsCString();
|
||||
aHost.mAddresses = mAddresses.AsCArray();
|
||||
aHost.mAddressesLength = mAddresses.GetLength();
|
||||
aHost.mTtl = mAddrRecord.GetTtl();
|
||||
aHost.mInfraIfIndex = Get<Core>().mInfraIfIndex;
|
||||
aState = static_cast<EntryState>(GetState());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Core::HostEntry::CopyInfoTo(Key &aKey, EntryState &aState) const
|
||||
{
|
||||
Error error;
|
||||
|
||||
SuccessOrExit(error = CopyKeyInfoTo(aKey, aState));
|
||||
|
||||
aKey.mName = mName.AsCString();
|
||||
aKey.mServiceType = nullptr;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::ServiceEntry
|
||||
|
||||
@@ -2198,9 +2264,10 @@ void Core::ServiceEntry::UpdateServiceTypes(void)
|
||||
// This method updates the `mServiceTypes` list adding or
|
||||
// removing this `ServiceEntry` info.
|
||||
//
|
||||
// It is called whenever `ServcieEntry` state gets changed or an
|
||||
// PTR record is added or removed. The service is valid when
|
||||
// entry is registered and we have a PTR with non-zero TTL.
|
||||
// It is called whenever the `ServiceEntry` state gets changed
|
||||
// or a PTR record is added or removed. The service is valid
|
||||
// when entry is registered and we have a PTR with non-zero
|
||||
// TTL.
|
||||
|
||||
bool shouldAdd = (GetState() == kRegistered) && mPtrRecord.CanAnswer();
|
||||
ServiceType *serviceType;
|
||||
@@ -2235,7 +2302,7 @@ void Core::ServiceEntry::UpdateServiceTypes(void)
|
||||
// the `mServiceTypes` list. It is safe to
|
||||
// remove here as this method will never be
|
||||
// called while we are iterating over the
|
||||
// `mServcieTypes` list.
|
||||
// `mServiceTypes` list.
|
||||
|
||||
Get<Core>().mServiceTypes.RemoveMatching(*serviceType);
|
||||
}
|
||||
@@ -2430,6 +2497,50 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
Error Core::ServiceEntry::CopyInfoTo(Service &aService, EntryState &aState, EntryIterator &aIterator) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(mPtrRecord.IsPresent(), error = kErrorNotFound);
|
||||
|
||||
aIterator.mSubTypeArray.Free();
|
||||
|
||||
for (const SubType &subType : mSubTypes)
|
||||
{
|
||||
SuccessOrAssert(aIterator.mSubTypeArray.PushBack(subType.mLabel.AsCString()));
|
||||
}
|
||||
|
||||
aService.mHostName = mHostName.AsCString();
|
||||
aService.mServiceInstance = mServiceInstance.AsCString();
|
||||
aService.mServiceType = mServiceType.AsCString();
|
||||
aService.mSubTypeLabels = aIterator.mSubTypeArray.AsCArray();
|
||||
aService.mSubTypeLabelsLength = aIterator.mSubTypeArray.GetLength();
|
||||
aService.mTxtData = mTxtData.GetBytes();
|
||||
aService.mTxtDataLength = mTxtData.GetLength();
|
||||
aService.mPort = mPort;
|
||||
aService.mPriority = mPriority;
|
||||
aService.mWeight = mWeight;
|
||||
aService.mTtl = mPtrRecord.GetTtl();
|
||||
aService.mInfraIfIndex = Get<Core>().mInfraIfIndex;
|
||||
aState = static_cast<EntryState>(GetState());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Core::ServiceEntry::CopyInfoTo(Key &aKey, EntryState &aState) const
|
||||
{
|
||||
Error error;
|
||||
|
||||
SuccessOrExit(error = CopyKeyInfoTo(aKey, aState));
|
||||
|
||||
aKey.mName = mServiceInstance.AsCString();
|
||||
aKey.mServiceType = mServiceType.AsCString();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::ServiceEntry::SubType
|
||||
|
||||
@@ -2486,9 +2597,9 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Core::ServiceType::Matches(const Name &aServcieTypeName) const
|
||||
bool Core::ServiceType::Matches(const Name &aServiceTypeName) const
|
||||
{
|
||||
return aServcieTypeName.Matches(/* aFirstLabel */ nullptr, mServiceType.AsCString(), kLocalDomain);
|
||||
return aServiceTypeName.Matches(/* aFirstLabel */ nullptr, mServiceType.AsCString(), kLocalDomain);
|
||||
}
|
||||
|
||||
bool Core::ServiceType::Matches(const Heap::String &aServiceType) const
|
||||
@@ -5984,6 +6095,103 @@ exit:
|
||||
|
||||
void Core::Ip4AddrCache::PrepareAQuestion(TxMessage &aQuery) { PrepareQueryQuestion(aQuery, ResourceRecord::kTypeA); }
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Core::Iterator
|
||||
|
||||
Core::EntryIterator::EntryIterator(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mType(kUnspecified)
|
||||
{
|
||||
}
|
||||
|
||||
Error Core::EntryIterator::GetNextHost(Host &aHost, EntryState &aState)
|
||||
{
|
||||
Error error = kErrorNotFound;
|
||||
|
||||
if (mType == kUnspecified)
|
||||
{
|
||||
mHostEntry = Get<Core>().mHostEntries.GetHead();
|
||||
mType = kHost;
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(mType == kHost, error = kErrorInvalidArgs);
|
||||
}
|
||||
|
||||
while (error == kErrorNotFound)
|
||||
{
|
||||
VerifyOrExit(mHostEntry != nullptr);
|
||||
error = mHostEntry->CopyInfoTo(aHost, aState);
|
||||
mHostEntry = mHostEntry->GetNext();
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Core::EntryIterator::GetNextService(Service &aService, EntryState &aState)
|
||||
{
|
||||
Error error = kErrorNotFound;
|
||||
|
||||
if (mType == kUnspecified)
|
||||
{
|
||||
mServiceEntry = Get<Core>().mServiceEntries.GetHead();
|
||||
mType = kService;
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(mType == kService, error = kErrorInvalidArgs);
|
||||
}
|
||||
|
||||
while (error == kErrorNotFound)
|
||||
{
|
||||
VerifyOrExit(mServiceEntry != nullptr);
|
||||
error = mServiceEntry->CopyInfoTo(aService, aState, *this);
|
||||
mServiceEntry = mServiceEntry->GetNext();
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Core::EntryIterator::GetNextKey(Key &aKey, EntryState &aState)
|
||||
{
|
||||
Error error = kErrorNotFound;
|
||||
|
||||
if (mType == kUnspecified)
|
||||
{
|
||||
mHostEntry = Get<Core>().mHostEntries.GetHead();
|
||||
mType = kHostKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit((mType == kServiceKey) || (mType == kHostKey), error = kErrorInvalidArgs);
|
||||
}
|
||||
|
||||
while ((error == kErrorNotFound) && (mType == kHostKey))
|
||||
{
|
||||
if (mHostEntry == nullptr)
|
||||
{
|
||||
mServiceEntry = Get<Core>().mServiceEntries.GetHead();
|
||||
mType = kServiceKey;
|
||||
break;
|
||||
}
|
||||
|
||||
error = mHostEntry->CopyInfoTo(aKey, aState);
|
||||
mHostEntry = mHostEntry->GetNext();
|
||||
}
|
||||
|
||||
while ((error == kErrorNotFound) && (mType == kServiceKey))
|
||||
{
|
||||
VerifyOrExit(mServiceEntry != nullptr);
|
||||
error = mServiceEntry->CopyInfoTo(aKey, aState);
|
||||
mServiceEntry = mServiceEntry->GetNext();
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Multicast
|
||||
} // namespace Dns
|
||||
} // namespace ot
|
||||
|
||||
+139
-16
@@ -46,6 +46,7 @@
|
||||
#include "common/heap_data.hpp"
|
||||
#include "common/heap_string.hpp"
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/owned_ptr.hpp"
|
||||
#include "common/owning_list.hpp"
|
||||
#include "common/retain_ptr.hpp"
|
||||
@@ -63,6 +64,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents an opaque (and empty) type for an mDNS iterator.
|
||||
*
|
||||
*/
|
||||
struct otMdnsIterator
|
||||
{
|
||||
};
|
||||
|
||||
namespace ot {
|
||||
namespace Dns {
|
||||
namespace Multicast {
|
||||
@@ -95,6 +104,7 @@ public:
|
||||
typedef otMdnsRequestId RequestId; ///< A request Identifier.
|
||||
typedef otMdnsRegisterCallback RegisterCallback; ///< Registration callback.
|
||||
typedef otMdnsConflictCallback ConflictCallback; ///< Conflict callback.
|
||||
typedef otMdnsEntryState EntryState; ///< Host/Service/Key entry state.
|
||||
typedef otMdnsHost Host; ///< Host information.
|
||||
typedef otMdnsService Service; ///< Service information.
|
||||
typedef otMdnsKey Key; ///< Key information.
|
||||
@@ -111,6 +121,7 @@ public:
|
||||
typedef otMdnsAddressCallback AddressCallback; ///< Address callback
|
||||
typedef otMdnsAddressResult AddressResult; ///< Address result.
|
||||
typedef otMdnsAddressAndTtl AddressAndTtl; ///< Address and TTL.
|
||||
typedef otMdnsIterator Iterator; ///< An entry iterator.
|
||||
|
||||
/**
|
||||
* Represents a socket address info.
|
||||
@@ -323,10 +334,11 @@ public:
|
||||
*
|
||||
* The fields in @p aKey follow these rules:
|
||||
*
|
||||
* - If the key is associated with a host entry, `mName` specifies the host name & `mServcieType` MUST be `nullptr`.
|
||||
* - If the key is associated with a service entry, `mName` specifies the service instance label (always treated as
|
||||
* a single label) and `mServiceType` specifies the service type (e.g. "_tst._udp"). In this case the DNS name
|
||||
* for key record is `<mName>.<mServiceTye>`.
|
||||
* - If the key is associated with a host entry, the `mName` field specifies the host name and the `mServiceType`
|
||||
* MUST be `nullptr`.
|
||||
* - If the key is associated with a service entry, the `mName` filed specifies the service instance label (always
|
||||
* treated as a single label) and the `mServiceType` filed specifies the service type (e.g. "_tst._udp"). In this
|
||||
* case the DNS name for key record is `<mName>.<mServiceTye>`.
|
||||
* - The `mKeyData` field contains the key record's data with `mKeyDataLength` as its length in byes.
|
||||
* - The `mTtl` specifies the TTL if non-zero. If zero, the mDNS module will use default TTL for the key entry.
|
||||
*
|
||||
@@ -351,10 +363,11 @@ public:
|
||||
*
|
||||
* The fields in @p aKey follow these rules:
|
||||
*
|
||||
* - If the key is associated with a host entry, `mName` specifies the host name & `mServcieType` MUST be `nullptr`.
|
||||
* - If the key is associated with a service entry, `mName` specifies the service instance label (always treated as
|
||||
* a single label) and `mServiceType` specifies the service type (e.g. "_tst._udp"). In this case the DNS name
|
||||
* for key record is `<mName>.<mServiceTye>`.
|
||||
* - If the key is associated with a host entry, the `mName` field specifies the host name and the `mServiceType`
|
||||
* MUST be `nullptr`.
|
||||
* - If the key is associated with a service entry, the `mName` filed specifies the service instance label (always
|
||||
* treated as a single label) and the `mServiceType` field specifies the service type (e.g. "_tst._udp"). In this
|
||||
* case the DNS name for key record is `<mName>.<mServiceTye>`.
|
||||
* - The rest of the fields in @p aKey structure are ignored in a`otMdnsUnregisterKey()` call.
|
||||
*
|
||||
* If there is no previously registered key with the same name, no action is performed.
|
||||
@@ -484,7 +497,7 @@ public:
|
||||
*
|
||||
* Initiates a continuous IPv6 address resolver for the specified host name in @p aResolver.
|
||||
*
|
||||
* Discovered addresses are reported through the `mCallback` function in @ p aResolver. The callback is invoked
|
||||
* Discovered addresses are reported through the `mCallback` function in @p aResolver. The callback is invoked
|
||||
* whenever addresses are added or removed, providing an updated list. If all addresses are removed, the callback
|
||||
* is invoked with an empty list (`mAddresses` will be NULL, and `mAddressesLength` will be zero).
|
||||
*
|
||||
@@ -521,7 +534,7 @@ public:
|
||||
*
|
||||
* Initiates a continuous IPv4 address resolver for the specified host name in @p aResolver.
|
||||
*
|
||||
* Discovered addresses are reported through the `mCallback` function in @ p aResolver. The IPv4 addresses are
|
||||
* Discovered addresses are reported through the `mCallback` function in @p aResolver. The IPv4 addresses are
|
||||
* represented using the IPv4-mapped IPv6 address format in `mAddresses` array. The callback is invoked whenever
|
||||
* addresses are added or removed, providing an updated list. If all addresses are removed, the callback is invoked
|
||||
* with an empty list (`mAddresses` will be NULL, and `mAddressesLength` will be zero).
|
||||
@@ -564,6 +577,72 @@ public:
|
||||
*/
|
||||
void SetMaxMessageSize(uint16_t aMaxSize) { mMaxMessageSize = aMaxSize; }
|
||||
|
||||
/**
|
||||
* Allocates a new iterator.
|
||||
*
|
||||
* @returns A pointer to the newly allocated iterator or `nullptr` if it fails to allocate.
|
||||
*
|
||||
*/
|
||||
Iterator *AllocateIterator(void);
|
||||
|
||||
/**
|
||||
* Frees a previously allocated iterator.
|
||||
*
|
||||
* @param[in] aIterator The iterator to free.
|
||||
*
|
||||
*/
|
||||
void FreeIterator(Iterator &aIterator);
|
||||
|
||||
/**
|
||||
* Iterates over registered host entries.
|
||||
*
|
||||
* On success, @p aHost is populated with information about the next host. Pointers within the `Host` structure
|
||||
* (like `mName`) remain valid until the next call to any OpenThread stack's public or platform API/callback.
|
||||
*
|
||||
* @param[in] aIterator The iterator to use.
|
||||
* @param[out] aHost A `Host` to return the information about the next host entry.
|
||||
* @param[out] aState An `EntryState` to return the entry state.
|
||||
*
|
||||
* @retval kErrorNone @p aHost, @p aState, & @p aIterator are updated successfully.
|
||||
* @retval kErrorNotFound Reached the end of the list.
|
||||
* @retval kErrorInvalidArg @p aIterator is not valid.
|
||||
*
|
||||
*/
|
||||
Error GetNextHost(Iterator &aIterator, Host &aHost, EntryState &aState) const;
|
||||
|
||||
/**
|
||||
* Iterates over registered service entries.
|
||||
*
|
||||
* On success, @p aService is populated with information about the next service. Pointers within the `Service`
|
||||
* structure (like `mServiceType`) remain valid until the next call to any OpenThread stack's public or platform
|
||||
* API/callback.
|
||||
*
|
||||
* @param[out] aService A `Service` to return the information about the next service entry.
|
||||
* @param[out] aState An `EntryState` to return the entry state.
|
||||
*
|
||||
* @retval kErrorNone @p aService, @p aState, & @p aIterator are updated successfully.
|
||||
* @retval kErrorNotFound Reached the end of the list.
|
||||
* @retval kErrorInvalidArg @p aIterator is not valid.
|
||||
*
|
||||
*/
|
||||
Error GetNextService(Iterator &aIterator, Service &aService, EntryState &aState) const;
|
||||
|
||||
/**
|
||||
* Iterates over registered key entries.
|
||||
*
|
||||
* On success, @p aKey is populated with information about the next key. Pointers within the `Key` structure
|
||||
* (like `mName`) remain valid until the next call to any OpenThread stack's public or platform API/callback.
|
||||
*
|
||||
* @param[out] aKey A `Key` to return the information about the next key entry.
|
||||
* @param[out] aState An `EntryState` to return the entry state.
|
||||
*
|
||||
* @retval kErrorNone @p aKey, @p aState, & @p aIterator are updated successfully.
|
||||
* @retval kErrorNotFound Reached the end of the list.
|
||||
* @retval kErrorInvalidArg @p aIterator is not valid.
|
||||
*
|
||||
*/
|
||||
Error GetNextKey(Iterator &aIterator, Key &aKey, EntryState &aState) const;
|
||||
|
||||
private:
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -626,6 +705,7 @@ private:
|
||||
class RxMessage;
|
||||
class ServiceEntry;
|
||||
class ServiceType;
|
||||
class EntryIterator;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -792,17 +872,19 @@ private:
|
||||
public:
|
||||
enum State : uint8_t
|
||||
{
|
||||
kProbing,
|
||||
kRegistered,
|
||||
kConflict,
|
||||
kRemoving,
|
||||
kProbing = OT_MDNS_ENTRY_STATE_PROBING,
|
||||
kRegistered = OT_MDNS_ENTRY_STATE_REGISTERED,
|
||||
kConflict = OT_MDNS_ENTRY_STATE_CONFLICT,
|
||||
kRemoving = OT_MDNS_ENTRY_STATE_REMOVING,
|
||||
};
|
||||
|
||||
State GetState(void) const { return mState; }
|
||||
bool HasKeyRecord(void) const { return mKeyRecord.IsPresent(); }
|
||||
void Register(const Key &aKey, const Callback &aCallback);
|
||||
void Unregister(const Key &aKey);
|
||||
void InvokeCallbacks(void);
|
||||
void ClearAppendState(void);
|
||||
Error CopyKeyInfoTo(Key &aKey, EntryState &aState) const;
|
||||
|
||||
protected:
|
||||
static constexpr uint32_t kMinIntervalProbeResponse = 250; // msec
|
||||
@@ -891,6 +973,8 @@ private:
|
||||
void ClearAppendState(void);
|
||||
void PrepareResponse(TxMessage &aResponse, TimeMilli aNow);
|
||||
void HandleConflict(void);
|
||||
Error CopyInfoTo(Host &aHost, EntryState &aState) const;
|
||||
Error CopyInfoTo(Key &aKey, EntryState &aState) const;
|
||||
|
||||
private:
|
||||
Error Init(Instance &aInstance, const char *aName);
|
||||
@@ -946,6 +1030,8 @@ private:
|
||||
void ClearAppendState(void);
|
||||
void PrepareResponse(TxMessage &aResponse, TimeMilli aNow);
|
||||
void HandleConflict(void);
|
||||
Error CopyInfoTo(Service &aService, EntryState &aState, EntryIterator &aIterator) const;
|
||||
Error CopyInfoTo(Key &aKey, EntryState &aState) const;
|
||||
|
||||
private:
|
||||
class SubType : public LinkedListEntry<SubType>, public Heap::Allocatable<SubType>, private ot::NonCopyable
|
||||
@@ -1021,7 +1107,7 @@ private:
|
||||
|
||||
public:
|
||||
Error Init(Instance &aInstance, const char *aServiceType);
|
||||
bool Matches(const Name &aServcieTypeName) const;
|
||||
bool Matches(const Name &aServiceTypeName) const;
|
||||
bool Matches(const Heap::String &aServiceType) const;
|
||||
bool Matches(const ServiceType &aServiceType) const { return (this == &aServiceType); }
|
||||
void IncrementNumEntries(void) { mNumEntries++; }
|
||||
@@ -1714,6 +1800,43 @@ private:
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
class EntryIterator : public Iterator, public InstanceLocator, public Heap::Allocatable<EntryIterator>
|
||||
{
|
||||
friend class Heap::Allocatable<EntryIterator>;
|
||||
friend class ServiceEntry;
|
||||
|
||||
public:
|
||||
Error GetNextHost(Host &aHost, EntryState &aState);
|
||||
Error GetNextService(Service &aService, EntryState &aState);
|
||||
Error GetNextKey(Key &aKey, EntryState &aState);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kArrayCapacityIncrement = 32;
|
||||
|
||||
enum Type : uint8_t
|
||||
{
|
||||
kUnspecified,
|
||||
kHost,
|
||||
kService,
|
||||
kHostKey,
|
||||
kServiceKey,
|
||||
};
|
||||
|
||||
explicit EntryIterator(Instance &aInstance);
|
||||
|
||||
Type mType;
|
||||
|
||||
union
|
||||
{
|
||||
const HostEntry *mHostEntry;
|
||||
const ServiceEntry *mServiceEntry;
|
||||
};
|
||||
|
||||
Heap::Array<const char *, kArrayCapacityIncrement> mSubTypeArray;
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
template <typename EntryType> OwningList<EntryType> &GetEntryList(void);
|
||||
template <typename EntryType, typename ItemInfo>
|
||||
Error Register(const ItemInfo &aItemInfo, RequestId aRequestId, RegisterCallback aCallback);
|
||||
@@ -1782,7 +1905,7 @@ private:
|
||||
CacheTask mCacheTask;
|
||||
};
|
||||
|
||||
// Specializations of `Core::GetEntryList()` for `HostEntry` and `ServcieEntry`:
|
||||
// Specializations of `Core::GetEntryList()` for `HostEntry` and `ServiceEntry`:
|
||||
|
||||
template <> inline OwningList<Core::HostEntry> &Core::GetEntryList<Core::HostEntry>(void) { return mHostEntries; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user