Skip to content

Commit

Permalink
[mdns] add APIs to iterate over registered host/service/key entries (o…
Browse files Browse the repository at this point in the history
  • Loading branch information
abtink committed Apr 22, 2024
1 parent 9af7203 commit 9681690
Show file tree
Hide file tree
Showing 7 changed files with 647 additions and 36 deletions.
2 changes: 1 addition & 1 deletion include/openthread/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
122 changes: 112 additions & 10 deletions include/openthread/mdns.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -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).
*
Expand Down Expand Up @@ -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).
Expand Down
141 changes: 138 additions & 3 deletions src/cli/cli_mdns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -458,6 +481,117 @@ template <> otError Mdns::Process<Cmd("unregister")>(Arg aArgs[])
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;
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/cli/cli_mdns.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class Mdns : private Utils
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[]);
Expand Down
42 changes: 42 additions & 0 deletions src/core/api/mdns_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 9681690

Please sign in to comment.