mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[mdns] add native mDNS support in OT (#9797)
This commit introduces native mDNS support within the OpenThread stack, implementing RFC 6762 compliant registration of hosts, services, and keys. It supports the following functionalities: - Sending probes to claim names. - Sending announcements on initial registration and changes. - Sending "goodbye" announcements when unregistered or upon record removal. - Negative responses (NSEC). - Support for service sub-types and their addition/removal. - Support for `_services._dns-sd._udp` queries (all service types). - Responding to queries (including "QU" questions). - Delay mechanism when responding to multi-question query messages, ensuring unique answers. - Providing extra records in the Additional Data section if not already in the Answer section (e.g., on a PTR query, include SRV and host AAAA addresses). - Implementing Known-Answer Suppression. - Supporting multi-packet queries with known answers in follow-up messages. - Rate-limiting record multicasts (once per second). - Rate-limiting probe responses (once per 250ms). - Detecting conflicts after probes. - Limiting the size of emitted responses or probes, breaking into multiple messages if necessary. - Detecting self originating messages (sent by mDNS module). - Support for service browser. - Support for service resolvers (SRV and TXT records) and IPv4/IPv6 address resolvers for hostnames. - Introduces smart cache management: - Passively caches service records for active browsers. - Passively caches address records for active service resolvers. - Enables multiple simultaneous browsers/resolvers for the same service/host. This commit introduces public `otMdns` OpenThread APIs and related CLI commands for the mDNS module. For platform abstraction, `otPlatMdns` APIs are defined in `mdns_socket.h` (e.g., to send or receive mDNS messages): - An implementation of the platform APIs is provided for posix. - Also under the simulation platform, a simplified implementation of the `otPlatMdns` APIs is provided (intended for testing). This commit also adds a detailed `test_mdns` unit test, validating various functionalities and covering potential edge cases.
This commit is contained in:
committed by
GitHub
parent
6de5cd8256
commit
bf41332061
@@ -58,6 +58,7 @@
|
||||
* @defgroup api-dnssd-server DNS-SD Server
|
||||
* @defgroup api-icmp6 ICMPv6
|
||||
* @defgroup api-ip6 IPv6
|
||||
* @defgroup api-mdns Multicast DNS
|
||||
* @defgroup api-nat64 NAT64
|
||||
* @defgroup api-srp SRP
|
||||
* @defgroup api-ping-sender Ping Sender
|
||||
@@ -181,6 +182,7 @@
|
||||
* @defgroup plat-memory Memory
|
||||
* @defgroup plat-messagepool Message Pool
|
||||
* @defgroup plat-misc Miscellaneous
|
||||
* @defgroup plat-mdns Multicast DNS
|
||||
* @defgroup plat-multipan Multipan
|
||||
* @defgroup plat-otns Network Simulator
|
||||
* @defgroup plat-radio Radio
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
* @defgroup config-mesh-forwarder Mesh Forwarder
|
||||
* @defgroup config-misc Miscellaneous Constants
|
||||
* @defgroup config-mle MLE Service
|
||||
* @defgroup config-mdns Multicast DNS
|
||||
* @defgroup config-nat64 NAT64
|
||||
* @defgroup config-netdata-publisher Network Data Publisher
|
||||
* @defgroup config-network-diagnostic Network Diagnostics
|
||||
|
||||
@@ -215,6 +215,7 @@ ot_option(OT_LINK_METRICS_SUBJECT OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENA
|
||||
ot_option(OT_LINK_RAW OPENTHREAD_CONFIG_LINK_RAW_ENABLE "link raw service")
|
||||
ot_option(OT_LOG_LEVEL_DYNAMIC OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE "dynamic log level control")
|
||||
ot_option(OT_MAC_FILTER OPENTHREAD_CONFIG_MAC_FILTER_ENABLE "mac filter")
|
||||
ot_option(OT_MDNS OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE "multicast DNS (mDNS)")
|
||||
ot_option(OT_MESH_DIAG OPENTHREAD_CONFIG_MESH_DIAG_ENABLE "mesh diag")
|
||||
ot_option(OT_MESSAGE_USE_HEAP OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE "heap allocator for message buffers")
|
||||
ot_option(OT_MLE_LONG_ROUTES OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE "MLE long routes extension (experimental)")
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MLR_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE 0
|
||||
#define OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE 1
|
||||
@@ -99,5 +100,6 @@
|
||||
#define OPENTHREAD_CONFIG_DNS_DSO_MOCK_PLAT_APIS_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_BORDER_ROUTING_MOCK_PLAT_APIS_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_MOCK_PLAT_APIS_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_MOCK_PLAT_APIS_ENABLE 1
|
||||
|
||||
#endif // OT_CORE_CONFIG_CHECK_SIZE_BR_H_
|
||||
|
||||
@@ -69,6 +69,7 @@ add_library(openthread-simulation
|
||||
flash.c
|
||||
infra_if.c
|
||||
logging.c
|
||||
mdns_socket.c
|
||||
misc.c
|
||||
multipan.c
|
||||
radio.c
|
||||
|
||||
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*/
|
||||
|
||||
#include "platform-simulation.h"
|
||||
|
||||
#include <openthread/nat64.h>
|
||||
#include <openthread/platform/mdns_socket.h>
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
#if OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
|
||||
|
||||
// Provide a simplified POSIX based implementation of `otPlatMdns`
|
||||
// platform APIs. This is intended for testing.
|
||||
|
||||
#include <openthread/ip6.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "simul_utils.h"
|
||||
#include "utils/code_utils.h"
|
||||
|
||||
#define MAX_BUFFER_SIZE 1600
|
||||
|
||||
#define MDNS_PORT 5353
|
||||
|
||||
static bool sEnabled = false;
|
||||
static uint32_t sInfraIfIndex;
|
||||
static int sMdnsFd4 = -1;
|
||||
static int sMdnsFd6 = -1;
|
||||
|
||||
/* this is a portability hack */
|
||||
#ifndef IPV6_ADD_MEMBERSHIP
|
||||
#ifdef IPV6_JOIN_GROUP
|
||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef IPV6_DROP_MEMBERSHIP
|
||||
#ifdef IPV6_LEAVE_GROUP
|
||||
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define VerifyOrDie(aCondition, aErrMsg) \
|
||||
do \
|
||||
{ \
|
||||
if (!(aCondition)) \
|
||||
{ \
|
||||
fprintf(stderr, "\n\r" aErrMsg ". errono:%s\n\r", strerror(errno)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
static void SetReuseAddrPort(int aFd)
|
||||
{
|
||||
int ret;
|
||||
int yes = 1;
|
||||
|
||||
ret = setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(SO_REUSEADDR) failed");
|
||||
|
||||
ret = setsockopt(aFd, SOL_SOCKET, SO_REUSEPORT, (char *)&yes, sizeof(yes));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(SO_REUSEPORT) failed");
|
||||
}
|
||||
|
||||
static void OpenIp4Socket(uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
int fd;
|
||||
int ret;
|
||||
uint8_t u8;
|
||||
int value;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
VerifyOrDie(fd >= 0, "socket() failed");
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
char nameBuffer[IF_NAMESIZE];
|
||||
const char *ifname;
|
||||
|
||||
ifname = if_indextoname(aInfraIfIndex, nameBuffer);
|
||||
VerifyOrDie(ifname != NULL, "if_indextoname() failed");
|
||||
|
||||
ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(SO_BINDTODEVICE) failed");
|
||||
}
|
||||
#else
|
||||
value = aInfraIfIndex;
|
||||
ret = setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &value, sizeof(value));
|
||||
#endif
|
||||
|
||||
u8 = 255;
|
||||
ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &u8, sizeof(u8));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IP_MULTICAST_TTL) failed");
|
||||
|
||||
value = 255;
|
||||
ret = setsockopt(fd, IPPROTO_IP, IP_TTL, &value, sizeof(value));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IP_TTL) failed");
|
||||
|
||||
u8 = 1;
|
||||
ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &u8, sizeof(u8));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IP_MULTICAST_LOOP) failed");
|
||||
|
||||
SetReuseAddrPort(fd);
|
||||
|
||||
{
|
||||
struct ip_mreqn mreqn;
|
||||
|
||||
memset(&mreqn, 0, sizeof(mreqn));
|
||||
mreqn.imr_multiaddr.s_addr = inet_addr("224.0.0.251");
|
||||
mreqn.imr_ifindex = aInfraIfIndex;
|
||||
|
||||
ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IP_MULTICAST_IF) failed");
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(MDNS_PORT);
|
||||
|
||||
ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
VerifyOrDie(ret >= 0, "bind() failed");
|
||||
|
||||
sMdnsFd4 = fd;
|
||||
}
|
||||
|
||||
static void JoinOrLeaveIp4MulticastGroup(bool aJoin, uint32_t aInfraIfIndex)
|
||||
{
|
||||
struct ip_mreqn mreqn;
|
||||
int ret;
|
||||
|
||||
memset(&mreqn, 0, sizeof(mreqn));
|
||||
mreqn.imr_multiaddr.s_addr = inet_addr("224.0.0.251");
|
||||
mreqn.imr_ifindex = aInfraIfIndex;
|
||||
|
||||
if (aJoin)
|
||||
{
|
||||
// Suggested workaround for netif not dropping
|
||||
// a previous multicast membership.
|
||||
setsockopt(sMdnsFd4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
|
||||
}
|
||||
|
||||
ret = setsockopt(sMdnsFd4, IPPROTO_IP, aJoin ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IP_ADD/DROP_MEMBERSHIP) failed");
|
||||
}
|
||||
|
||||
static void OpenIp6Socket(uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
|
||||
struct sockaddr_in6 addr6;
|
||||
int fd;
|
||||
int ret;
|
||||
int value;
|
||||
|
||||
fd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
VerifyOrDie(fd >= 0, "socket() failed");
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
char nameBuffer[IF_NAMESIZE];
|
||||
const char *ifname;
|
||||
|
||||
ifname = if_indextoname(aInfraIfIndex, nameBuffer);
|
||||
VerifyOrDie(ifname != NULL, "if_indextoname() failed");
|
||||
|
||||
ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(SO_BINDTODEVICE) failed");
|
||||
}
|
||||
#else
|
||||
value = aInfraIfIndex;
|
||||
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, &value, sizeof(value));
|
||||
#endif
|
||||
|
||||
value = 255;
|
||||
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &value, sizeof(value));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IPV6_MULTICAST_HOPS) failed");
|
||||
|
||||
value = 255;
|
||||
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &value, sizeof(value));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IPV6_UNICAST_HOPS) failed");
|
||||
|
||||
value = 1;
|
||||
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IPV6_V6ONLY) failed");
|
||||
|
||||
value = aInfraIfIndex;
|
||||
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &value, sizeof(value));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IPV6_MULTICAST_IF) failed");
|
||||
|
||||
value = 1;
|
||||
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &value, sizeof(value));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IPV6_MULTICAST_LOOP) failed");
|
||||
|
||||
SetReuseAddrPort(fd);
|
||||
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(MDNS_PORT);
|
||||
|
||||
ret = bind(fd, (struct sockaddr *)&addr6, sizeof(addr6));
|
||||
VerifyOrDie(ret >= 0, "bind() failed");
|
||||
|
||||
sMdnsFd6 = fd;
|
||||
}
|
||||
|
||||
static void JoinOrLeaveIp6MulticastGroup(bool aJoin, uint32_t aInfraIfIndex)
|
||||
{
|
||||
struct ipv6_mreq mreq6;
|
||||
int ret;
|
||||
|
||||
memset(&mreq6, 0, sizeof(mreq6));
|
||||
|
||||
inet_pton(AF_INET6, "ff02::fb", &mreq6.ipv6mr_multiaddr);
|
||||
mreq6.ipv6mr_interface = (int)aInfraIfIndex;
|
||||
|
||||
if (aJoin)
|
||||
{
|
||||
// Suggested workaround for netif not dropping
|
||||
// a previous multicast membership.
|
||||
setsockopt(sMdnsFd6, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
|
||||
}
|
||||
|
||||
ret = setsockopt(sMdnsFd6, IPPROTO_IPV6, aJoin ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
|
||||
VerifyOrDie(ret >= 0, "setsocketopt(IP6_ADD/DROP_MEMBERSHIP) failed");
|
||||
}
|
||||
|
||||
otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
if (aEnable)
|
||||
{
|
||||
otEXPECT(!sEnabled);
|
||||
|
||||
OpenIp4Socket(aInfraIfIndex);
|
||||
JoinOrLeaveIp4MulticastGroup(/* aJoin */ true, aInfraIfIndex);
|
||||
OpenIp6Socket(aInfraIfIndex);
|
||||
JoinOrLeaveIp6MulticastGroup(/* aJoin */ true, aInfraIfIndex);
|
||||
|
||||
sEnabled = true;
|
||||
sInfraIfIndex = aInfraIfIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
otEXPECT(sEnabled);
|
||||
|
||||
JoinOrLeaveIp4MulticastGroup(/* aJoin */ false, aInfraIfIndex);
|
||||
JoinOrLeaveIp6MulticastGroup(/* aJoin */ false, aInfraIfIndex);
|
||||
close(sMdnsFd4);
|
||||
close(sMdnsFd6);
|
||||
sEnabled = false;
|
||||
}
|
||||
|
||||
exit:
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
|
||||
uint8_t buffer[MAX_BUFFER_SIZE];
|
||||
uint16_t length;
|
||||
int bytes;
|
||||
|
||||
otEXPECT(sEnabled);
|
||||
|
||||
length = otMessageRead(aMessage, 0, buffer, sizeof(buffer));
|
||||
otMessageFree(aMessage);
|
||||
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr("224.0.0.251");
|
||||
addr.sin_port = htons(MDNS_PORT);
|
||||
|
||||
bytes = sendto(sMdnsFd4, buffer, length, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
VerifyOrDie((bytes == length), "sendTo(sMdnsFd4) failed");
|
||||
}
|
||||
|
||||
{
|
||||
struct sockaddr_in6 addr6;
|
||||
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(MDNS_PORT);
|
||||
inet_pton(AF_INET6, "ff02::fb", &addr6.sin6_addr);
|
||||
|
||||
bytes = sendto(sMdnsFd6, buffer, length, 0, (struct sockaddr *)&addr6, sizeof(addr6));
|
||||
|
||||
VerifyOrDie((bytes == length), "sendTo(sMdnsFd6) failed");
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void otPlatMdnsSendUnicast(otInstance *aInstance, otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otIp4Address ip4Addr;
|
||||
uint8_t buffer[MAX_BUFFER_SIZE];
|
||||
uint16_t length;
|
||||
int bytes;
|
||||
|
||||
otEXPECT(sEnabled);
|
||||
|
||||
length = otMessageRead(aMessage, 0, buffer, sizeof(buffer));
|
||||
otMessageFree(aMessage);
|
||||
|
||||
if (otIp4FromIp4MappedIp6Address(&aAddress->mAddress, &ip4Addr) == OT_ERROR_NONE)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
memcpy(&addr.sin_addr.s_addr, &ip4Addr, sizeof(otIp4Address));
|
||||
addr.sin_port = htons(MDNS_PORT);
|
||||
|
||||
bytes = sendto(sMdnsFd4, buffer, length, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
VerifyOrDie((bytes == length), "sendTo(sMdnsFd4) failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in6 addr6;
|
||||
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(MDNS_PORT);
|
||||
memcpy(&addr6.sin6_addr, &aAddress->mAddress, sizeof(otIp6Address));
|
||||
|
||||
bytes = sendto(sMdnsFd6, buffer, length, 0, (struct sockaddr *)&addr6, sizeof(addr6));
|
||||
|
||||
VerifyOrDie((bytes == length), "sendTo(sMdnsFd6) failed");
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void platformMdnsSocketUpdateFdSet(fd_set *aReadFdSet, int *aMaxFd)
|
||||
{
|
||||
otEXPECT(sEnabled);
|
||||
|
||||
utilsAddFdToFdSet(sMdnsFd4, aReadFdSet, aMaxFd);
|
||||
utilsAddFdToFdSet(sMdnsFd6, aReadFdSet, aMaxFd);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void platformMdnsSocketProcess(otInstance *aInstance, const fd_set *aReadFdSet)
|
||||
{
|
||||
otEXPECT(sEnabled);
|
||||
|
||||
if (FD_ISSET(sMdnsFd4, aReadFdSet))
|
||||
{
|
||||
uint8_t buffer[MAX_BUFFER_SIZE];
|
||||
struct sockaddr_in sockaddr;
|
||||
otPlatMdnsAddressInfo addrInfo;
|
||||
otMessage *message;
|
||||
socklen_t len = sizeof(sockaddr);
|
||||
ssize_t rval;
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
rval = recvfrom(sMdnsFd4, (char *)&buffer, sizeof(buffer), 0, (struct sockaddr *)&sockaddr, &len);
|
||||
|
||||
VerifyOrDie(rval >= 0, "recvfrom() failed");
|
||||
|
||||
message = otIp6NewMessage(aInstance, NULL);
|
||||
VerifyOrDie(message != NULL, "otIp6NewMessage() failed");
|
||||
|
||||
VerifyOrDie(otMessageAppend(message, buffer, (uint16_t)rval) == OT_ERROR_NONE, "otMessageAppend() failed");
|
||||
|
||||
memset(&addrInfo, 0, sizeof(addrInfo));
|
||||
otIp4ToIp4MappedIp6Address((otIp4Address *)(&sockaddr.sin_addr.s_addr), &addrInfo.mAddress);
|
||||
addrInfo.mPort = MDNS_PORT;
|
||||
addrInfo.mInfraIfIndex = sInfraIfIndex;
|
||||
|
||||
otPlatMdnsHandleReceive(aInstance, message, /* aInUnicast */ false, &addrInfo);
|
||||
}
|
||||
|
||||
if (FD_ISSET(sMdnsFd6, aReadFdSet))
|
||||
{
|
||||
uint8_t buffer[MAX_BUFFER_SIZE];
|
||||
struct sockaddr_in6 sockaddr6;
|
||||
otPlatMdnsAddressInfo addrInfo;
|
||||
otMessage *message;
|
||||
socklen_t len = sizeof(sockaddr6);
|
||||
ssize_t rval;
|
||||
|
||||
memset(&sockaddr6, 0, sizeof(sockaddr6));
|
||||
rval = recvfrom(sMdnsFd6, (char *)&buffer, sizeof(buffer), 0, (struct sockaddr *)&sockaddr6, &len);
|
||||
VerifyOrDie(rval >= 0, "recvfrom(sMdnsFd6) failed");
|
||||
|
||||
message = otIp6NewMessage(aInstance, NULL);
|
||||
VerifyOrDie(message != NULL, "otIp6NewMessage() failed");
|
||||
|
||||
VerifyOrDie(otMessageAppend(message, buffer, (uint16_t)rval) == OT_ERROR_NONE, "otMessageAppend() failed");
|
||||
|
||||
memset(&addrInfo, 0, sizeof(addrInfo));
|
||||
memcpy(&addrInfo.mAddress, &sockaddr6.sin6_addr, sizeof(otIp6Address));
|
||||
addrInfo.mPort = MDNS_PORT;
|
||||
addrInfo.mInfraIfIndex = sInfraIfIndex;
|
||||
|
||||
otPlatMdnsHandleReceive(aInstance, message, /* aInUnicast */ false, &addrInfo);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Add weak implementation of `ot` APIs for RCP build. Note that
|
||||
// `simulation` platform does not get `OPENTHREAD_RADIO` config)
|
||||
|
||||
OT_TOOL_WEAK uint16_t otMessageRead(const otMessage *aMessage, uint16_t aOffset, void *aBuf, uint16_t aLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aMessage);
|
||||
OT_UNUSED_VARIABLE(aOffset);
|
||||
OT_UNUSED_VARIABLE(aBuf);
|
||||
OT_UNUSED_VARIABLE(aLength);
|
||||
|
||||
fprintf(stderr, "\n\rWeak otMessageRead() is incorrectly used\n\r");
|
||||
exit(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otMessageFree(otMessage *aMessage)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aMessage);
|
||||
fprintf(stderr, "\n\rWeak otMessageFree() is incorrectly used\n\r");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otMessage *otIp6NewMessage(otInstance *aInstance, const otMessageSettings *aSettings)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aSettings);
|
||||
|
||||
fprintf(stderr, "\n\rWeak otIp6NewMessage() is incorrectly used\n\r");
|
||||
exit(1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otMessageAppend(otMessage *aMessage, const void *aBuf, uint16_t aLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aMessage);
|
||||
OT_UNUSED_VARIABLE(aBuf);
|
||||
OT_UNUSED_VARIABLE(aLength);
|
||||
|
||||
fprintf(stderr, "\n\rWeak otMessageFree() is incorrectly used\n\r");
|
||||
exit(1);
|
||||
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otIp4ToIp4MappedIp6Address(const otIp4Address *aIp4Address, otIp6Address *aIp6Address)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aIp4Address);
|
||||
OT_UNUSED_VARIABLE(aIp6Address);
|
||||
|
||||
fprintf(stderr, "\n\rWeak otIp4ToIp4MappedIp6Address() is incorrectly used\n\r");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otIp4FromIp4MappedIp6Address(const otIp6Address *aIp6Address, otIp4Address *aIp4Address)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aIp6Address);
|
||||
OT_UNUSED_VARIABLE(aIp4Address);
|
||||
|
||||
fprintf(stderr, "\n\rWeak otIp4FromIp4MappedIp6Address() is incorrectly used\n\r");
|
||||
exit(1);
|
||||
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatMdnsHandleReceive(otInstance *aInstance,
|
||||
otMessage *aMessage,
|
||||
bool aIsUnicast,
|
||||
const otPlatMdnsAddressInfo *aAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aMessage);
|
||||
OT_UNUSED_VARIABLE(aIsUnicast);
|
||||
OT_UNUSED_VARIABLE(aAddress);
|
||||
|
||||
fprintf(stderr, "\n\rWeak otPlatMdnsHandleReceive() is incorrectly used\n\r");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
#else // OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
|
||||
|
||||
otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aEnable);
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
|
||||
otMessageFree(aMessage);
|
||||
}
|
||||
|
||||
void otPlatMdnsSendUnicast(otInstance *aInstance, otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aAddress);
|
||||
otMessageFree(aMessage);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
@@ -103,3 +103,16 @@
|
||||
#ifndef OPENTHREAD_SIMULATION_MAX_NETWORK_SIZE
|
||||
#define OPENTHREAD_SIMULATION_MAX_NETWORK_SIZE 33
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
|
||||
*
|
||||
* Define as 1 for the simulation platform to provide a simplified implementation of `otPlatMdns` APIs using posix
|
||||
* socket.
|
||||
*
|
||||
* This is intended for testing of the OpenThread Multicast DNS (mDNS) module.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
|
||||
#define OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX 0
|
||||
#endif
|
||||
|
||||
@@ -341,6 +341,28 @@ void platformInfraIfProcess(otInstance *aInstance, const fd_set *aReadFdSet, con
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
|
||||
|
||||
/**
|
||||
* Updates the file descriptor sets with file descriptors used by the mDNS socket.
|
||||
*
|
||||
* @param[in,out] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[in,out] aMaxFd A pointer to the max file descriptor.
|
||||
*
|
||||
*/
|
||||
void platformMdnsSocketUpdateFdSet(fd_set *aReadFdSet, int *aMaxFd);
|
||||
|
||||
/**
|
||||
* Performs mDNs Socket processing.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aReadFdSet A pointer to the read file descriptors.
|
||||
*
|
||||
*/
|
||||
void platformMdnsSocketProcess(otInstance *aInstance, const fd_set *aReadFdSet);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Shuts down the BLE service used by OpenThread.
|
||||
*
|
||||
|
||||
@@ -295,6 +295,9 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
platformInfraIfUpdateFdSet(&read_fds, &write_fds, &max_fd);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
|
||||
platformMdnsSocketUpdateFdSet(&read_fds, &max_fd);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
|
||||
platformBleUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
|
||||
@@ -329,6 +332,9 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
platformInfraIfProcess(aInstance, &read_fds, &write_fds);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
|
||||
platformMdnsSocketProcess(aInstance, &read_fds);
|
||||
#endif
|
||||
|
||||
if (gTerminate)
|
||||
{
|
||||
|
||||
@@ -73,6 +73,7 @@ source_set("openthread") {
|
||||
"link_metrics.h",
|
||||
"link_raw.h",
|
||||
"logging.h",
|
||||
"mdns.h",
|
||||
"mesh_diag.h",
|
||||
"message.h",
|
||||
"multi_radio.h",
|
||||
@@ -97,6 +98,7 @@ source_set("openthread") {
|
||||
"platform/flash.h",
|
||||
"platform/infra_if.h",
|
||||
"platform/logging.h",
|
||||
"platform/mdns_socket.h",
|
||||
"platform/memory.h",
|
||||
"platform/messagepool.h",
|
||||
"platform/misc.h",
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (403)
|
||||
#define OPENTHREAD_API_VERSION (404)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -0,0 +1,747 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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
|
||||
* @brief
|
||||
* This file includes the mDNS related APIs.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_MULTICAST_DNS_H_
|
||||
#define OPENTHREAD_MULTICAST_DNS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/platform/dnssd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup api-mdns
|
||||
*
|
||||
* @brief
|
||||
* This module includes APIs for Multicast DNS (mDNS).
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* The mDNS APIs are available when the mDNS support `OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE` is enabled and the
|
||||
* `OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE` is also enabled.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a request ID (`uint32_t` value) for registering a host, a service, or a key service.
|
||||
*
|
||||
*/
|
||||
typedef otPlatDnssdRequestId otMdnsRequestId;
|
||||
|
||||
/**
|
||||
* Represents the callback function to report the outcome of a host, service, or key registration request.
|
||||
*
|
||||
* The outcome of a registration request is reported back by invoking this callback with one of the following `aError`
|
||||
* inputs:
|
||||
*
|
||||
* - `OT_ERROR_NONE` indicates registration was successful.
|
||||
* - `OT_ERROR_DUPLICATED` indicates a name conflict while probing, i.e., name is claimed by another mDNS responder.
|
||||
*
|
||||
* See `otMdnsRegisterHost()`, `otMdnsRegisterService()`, and `otMdnsRegisterKey()` for more details about when
|
||||
* the callback will be invoked.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aRequestId The request ID.
|
||||
* @param[in] aError Error indicating the outcome of request.
|
||||
*
|
||||
*/
|
||||
typedef otPlatDnssdRegisterCallback otMdnsRegisterCallback;
|
||||
|
||||
/**
|
||||
* Represents the callback function to report a detected name conflict after successful registration of an entry.
|
||||
*
|
||||
* If a conflict is detected while registering an entry, it is reported through the provided `otMdnsRegisterCallback`.
|
||||
* The `otMdnsConflictCallback` is used only when a name conflict is detected after an entry has been successfully
|
||||
* registered.
|
||||
*
|
||||
* A non-NULL @p aServiceType indicates that conflict is for a service entry. In this case @p aName specifies the
|
||||
* service instance label (treated as as a single DNS label and can potentially include dot `.` character).
|
||||
*
|
||||
* A NULL @p aServiceType indicates that conflict is for a host entry. In this case @p Name specifies the host name. It
|
||||
* does not include the domain name.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aName The host name or the service instance label.
|
||||
* @param[in] aServiceType The service type (e.g., `_tst._udp`).
|
||||
*
|
||||
*/
|
||||
typedef void (*otMdnsConflictCallback)(otInstance *aInstance, const char *aName, const char *aServiceType);
|
||||
|
||||
/**
|
||||
* Represents an mDNS host.
|
||||
*
|
||||
* This type is used to register or unregister a host (`otMdnsRegisterHost()` and `otMdnsUnregisterHost()`).
|
||||
*
|
||||
* See the description of each function for more details on how different fields are used in each case.
|
||||
*
|
||||
*/
|
||||
typedef otPlatDnssdHost otMdnsHost;
|
||||
|
||||
/**
|
||||
* Represents an mDNS service.
|
||||
*
|
||||
* This type is used to register or unregister a service (`otMdnsRegisterService()` and `otMdnsUnregisterService()`).
|
||||
*
|
||||
* See the description of each function for more details on how different fields are used in each case.
|
||||
*
|
||||
*/
|
||||
typedef otPlatDnssdService otMdnsService;
|
||||
|
||||
/**
|
||||
* Represents an mDNS key record.
|
||||
*
|
||||
* See `otMdnsRegisterKey()`, `otMdnsUnregisterKey()` for more details about fields in each case.
|
||||
*
|
||||
*/
|
||||
typedef otPlatDnssdKey otMdnsKey;
|
||||
|
||||
/**
|
||||
* Enables or disables the mDNS module.
|
||||
*
|
||||
* The mDNS module should be enabled before registration any host, service, or key entries. Disabling mDNS will
|
||||
* immediately stop all operations and any communication (multicast or unicast tx) and remove any previously registered
|
||||
* entries without sending any "goodbye" announcements or invoking their callback. Once disabled, all currently active
|
||||
* browsers and resolvers are stopped.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aEnable Boolean to indicate whether to enable (on `TRUE`) or disable (on `FALSE`).
|
||||
* @param[in] aInfraIfIndex The network interface index for mDNS operation. Value is ignored when disabling
|
||||
*
|
||||
* @retval OT_ERROR_NONE Enabled or disabled the mDNS module successfully.
|
||||
* @retval OT_ERROR_ALREADY mDNS is already enabled on an enable request or is already disabled on a disable request.
|
||||
*
|
||||
*/
|
||||
otError otMdnsSetEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex);
|
||||
|
||||
/**
|
||||
* Indicates whether the mDNS module is enabled.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*
|
||||
* @retval TRUE The mDNS module is enabled
|
||||
* @retval FALSE The mDNS module is disabled.
|
||||
*
|
||||
*/
|
||||
bool otMdnsIsEnabled(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Sets whether the mDNS module is allowed to send questions requesting unicast responses referred to as "QU" questions.
|
||||
*
|
||||
* The "QU" questions request unicast responses, in contrast to "QM" questions which request multicast responses.
|
||||
*
|
||||
* When allowed, the first probe will be sent as a "QU" question. This API can be used to address platform limitation
|
||||
* where platform socket cannot accept unicast response received on mDNS port (due to it being already bound).
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aAllow Indicates whether or not to allow "QU" questions.
|
||||
*
|
||||
*/
|
||||
void otMdnsSetQuestionUnicastAllowed(otInstance *aInstance, bool aAllow);
|
||||
|
||||
/**
|
||||
* Indicates whether mDNS module is allowed to send "QU" questions requesting unicast response.
|
||||
*
|
||||
* @retval TRUE The mDNS module is allowed to send "QU" questions.
|
||||
* @retval FALSE The mDNS module is not allowed to send "QU" questions.
|
||||
*
|
||||
*/
|
||||
bool otMdnsIsQuestionUnicastAllowed(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Sets the post-registration conflict callback.
|
||||
*
|
||||
* If a conflict is detected while registering an entry, it is reported through the provided `otMdnsRegisterCallback`.
|
||||
* The `otMdnsConflictCallback` is used only when a name conflict is detected after an entry has been successfully
|
||||
* registered.
|
||||
*
|
||||
* @p aCallback can be set to `NULL` if not needed. Subsequent calls will replace any previously set callback.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aCallback The conflict callback.
|
||||
*
|
||||
*/
|
||||
void otMdnsSetConflictCallback(otInstance *aInstance, otMdnsConflictCallback aCallback);
|
||||
|
||||
/**
|
||||
* Registers or updates a host on mDNS.
|
||||
*
|
||||
* The fields in @p aHost follow these rules:
|
||||
*
|
||||
* - The `mHostName` field specifies the host name to register (e.g., "myhost"). MUST NOT contain the domain name.
|
||||
* - The `mAddresses` is array of IPv6 addresses to register with the host. `mAddressesLength` provides the number of
|
||||
* entries in `mAddresses` array.
|
||||
* - The `mAddresses` array can be empty with zero `mAddressesLength`. In this case, mDNS will treat it as if host is
|
||||
* unregistered and stops advertising any addresses for this the host name.
|
||||
* - The `mTtl` specifies the TTL if non-zero. If zero, the mDNS core will choose the default TTL of 120 seconds.
|
||||
* - Other fields in @p aHost structure are ignored in an `otMdnsRegisterHost()` call.
|
||||
*
|
||||
* This function can be called again for the same `mHostName` to update a previously registered host entry, for example,
|
||||
* to change the list of addresses of the host. In this case, the mDNS module will send "goodbye" announcements for any
|
||||
* previously registered and now removed addresses and announce any newly added addresses.
|
||||
*
|
||||
* The outcome of the registration request is reported back by invoking the provided @p aCallback with @p aRequestId
|
||||
* as its input and one of the following `aError` inputs:
|
||||
*
|
||||
* - `OT_ERROR_NONE` indicates registration was successful.
|
||||
* - `OT_ERROR_DULICATED` indicates a name conflict while probing, i.e., name is claimed by another mDNS responder.
|
||||
*
|
||||
* For caller convenience, the OpenThread mDNS module guarantees that the callback will be invoked after this function
|
||||
* returns, even in cases of immediate registration success. The @p aCallback can be `NULL` if caller does not want to
|
||||
* be notified of the outcome.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aHost Information about the host to register.
|
||||
* @param[in] aRequestId The ID associated with this request.
|
||||
* @param[in] aCallback The callback function pointer to report the outcome (can be NULL if not needed).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started registration. @p aCallback will report the outcome.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsRegisterHost(otInstance *aInstance,
|
||||
const otMdnsHost *aHost,
|
||||
otMdnsRequestId aRequestId,
|
||||
otMdnsRegisterCallback aCallback);
|
||||
|
||||
/**
|
||||
* Unregisters a host on mDNS.
|
||||
*
|
||||
* The fields in @p aHost follow these rules:
|
||||
*
|
||||
* - The `mHostName` field specifies the host name to unregister (e.g., "myhost"). MUST NOT contain the domain name.
|
||||
* - Other fields in @p aHost structure are ignored in an `otMdnsUnregisterHost()` call.
|
||||
*
|
||||
* If there is no previously registered host with the same name, no action is performed.
|
||||
*
|
||||
* If there is a previously registered host with the same name, the mDNS module will send "goodbye" announcement for
|
||||
* all previously advertised address records.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aHost Information about the host to unregister.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully unregistered host.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsUnregisterHost(otInstance *aInstance, const otMdnsHost *aHost);
|
||||
|
||||
/**
|
||||
* Registers or updates a service on mDNS.
|
||||
*
|
||||
* The fields in @p aService follow these rules:
|
||||
*
|
||||
* - The `mServiceInstance` specifies the service instance label. It is treated as a single DNS name label. It may
|
||||
* contain dot `.` character which is allowed in a service instance label.
|
||||
* - The `mServiceType` specifies the service type (e.g., "_tst._udp"). It is treated as multiple dot `.` separated
|
||||
* labels. It MUST NOT contain the domain name.
|
||||
* - The `mHostName` field specifies the host name of the service. MUST NOT contain the domain name.
|
||||
* - The `mSubTypeLabels` is an array of strings representing sub-types associated with the service. Each array entry
|
||||
* is a sub-type label. The `mSubTypeLabels can be NULL if there is no sub-type. Otherwise, the array length is
|
||||
* specified by `mSubTypeLabelsLength`.
|
||||
* - The `mTxtData` and `mTxtDataLength` specify the encoded TXT data. The `mTxtData` can be NULL or `mTxtDataLength`
|
||||
* can be zero to specify an empty TXT data. In this case mDNS module will use a single zero byte `[ 0 ]` as the
|
||||
* TXT data.
|
||||
* - The `mPort`, `mWeight`, and `mPriority` specify the service's parameters as specified in DNS SRV record.
|
||||
* - 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 aService structure are ignored in an `otMdnsRegisterService()` call.
|
||||
*
|
||||
* This function can be called again for the same `mServiceInstance` and `mServiceType` to update a previously
|
||||
* registered service entry, for example, to change the sub-types list, or update any parameter such as port, weight,
|
||||
* priority, TTL, or host name. The mDNS module will send announcements for any changed info, e.g., will send "goodbye"
|
||||
* announcements for any removed sub-types and announce any newly added sub-types.
|
||||
*
|
||||
* Regarding the invocation of the @p aCallback, this function behaves in the same way as described in
|
||||
* `otMdnsRegisterHost()`.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aService Information about the service to register.
|
||||
* @param[in] aRequestId The ID associated with this request.
|
||||
* @param[in] aCallback The callback function pointer to report the outcome (can be NULL if not needed).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started registration. @p aCallback will report the outcome.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsRegisterService(otInstance *aInstance,
|
||||
const otMdnsService *aService,
|
||||
otMdnsRequestId aRequestId,
|
||||
otMdnsRegisterCallback aCallback);
|
||||
|
||||
/**
|
||||
* Unregisters a service on mDNS module.
|
||||
*
|
||||
* The fields in @p aService follow these rules:
|
||||
|
||||
* - The `mServiceInstance` specifies the service instance label. It is treated as a single DNS name label. It may
|
||||
* contain dot `.` character which is allowed in a service instance label.
|
||||
* - The `mServiceType` specifies the service type (e.g., "_tst._udp"). It is treated as multiple dot `.` separated
|
||||
* labels. It MUST NOT contain the domain name.
|
||||
* - Other fields in @p aService structure are ignored in an `otMdnsUnregisterService()` call.
|
||||
*
|
||||
* If there is no previously registered service with the same name, no action is performed.
|
||||
*
|
||||
* If there is a previously registered service with the same name, the mDNS module will send "goodbye" announcements
|
||||
* for all related records.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aService Information about the service to unregister.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully unregistered service.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsUnregisterService(otInstance *aInstance, const otMdnsService *aService);
|
||||
|
||||
/**
|
||||
* Registers or updates a key record on mDNS module.
|
||||
*
|
||||
* 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>`.
|
||||
* - 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.
|
||||
*
|
||||
* This function can be called again for the same name to updated a previously registered key entry, for example, to
|
||||
* change the key data or TTL.
|
||||
*
|
||||
* Regarding the invocation of the @p aCallback, this function behaves in the same way as described in
|
||||
* `otMdnsRegisterHost()`.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aKey Information about the key record to register.
|
||||
* @param[in] aRequestId The ID associated with this request.
|
||||
* @param[in] aCallback The callback function pointer to report the outcome (can be NULL if not needed).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started registration. @p aCallback will report the outcome.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsRegisterKey(otInstance *aInstance,
|
||||
const otMdnsKey *aKey,
|
||||
otMdnsRequestId aRequestId,
|
||||
otMdnsRegisterCallback aCallback);
|
||||
|
||||
/**
|
||||
* Unregisters a key record on mDNS.
|
||||
*
|
||||
* 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>`.
|
||||
* - 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.
|
||||
*
|
||||
* If there is a previously registered key with the same name, the mDNS module will send "goodbye" announcements for
|
||||
* the key record.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aKey Information about the key to unregister.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully unregistered key
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsUnregisterKey(otInstance *aInstance, const otMdnsKey *aKey);
|
||||
|
||||
typedef struct otMdnsBrowseResult otMdnsBrowseResult;
|
||||
typedef struct otMdnsSrvResult otMdnsSrvResult;
|
||||
typedef struct otMdnsTxtResult otMdnsTxtResult;
|
||||
typedef struct otMdnsAddressResult otMdnsAddressResult;
|
||||
|
||||
/**
|
||||
* Represents the callback function used to report a browse result.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResult The browse result.
|
||||
*
|
||||
*/
|
||||
typedef void (*otMdnsBrowseCallback)(otInstance *aInstance, const otMdnsBrowseResult *aResult);
|
||||
|
||||
/**
|
||||
* Represents the callback function used to report an SRV resolve result.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResult The SRV resolve result.
|
||||
*
|
||||
*/
|
||||
typedef void (*otMdnsSrvCallback)(otInstance *aInstance, const otMdnsSrvResult *aResult);
|
||||
|
||||
/**
|
||||
* Represents the callback function used to report a TXT resolve result.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResult The TXT resolve result.
|
||||
*
|
||||
*/
|
||||
typedef void (*otMdnsTxtCallback)(otInstance *aInstance, const otMdnsTxtResult *aResult);
|
||||
|
||||
/**
|
||||
* Represents the callback function use to report a IPv6/IPv4 address resolve result.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResult The address resolve result.
|
||||
*
|
||||
*/
|
||||
typedef void (*otMdnsAddressCallback)(otInstance *aInstance, const otMdnsAddressResult *aResult);
|
||||
|
||||
/**
|
||||
* Represents a service browser.
|
||||
*
|
||||
*/
|
||||
typedef struct otMdnsBrowser
|
||||
{
|
||||
const char *mServiceType; ///< The service type (e.g., "_mt._udp"). MUST NOT include domain name.
|
||||
const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise.
|
||||
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
|
||||
otMdnsBrowseCallback mCallback; ///< The callback to report result.
|
||||
} otMdnsBrowser;
|
||||
|
||||
/**
|
||||
* Represents a browse result.
|
||||
*
|
||||
*/
|
||||
struct otMdnsBrowseResult
|
||||
{
|
||||
const char *mServiceType; ///< The service type (e.g., "_mt._udp").
|
||||
const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise.
|
||||
const char *mServiceInstance; ///< Service instance label.
|
||||
uint32_t mTtl; ///< TTL in seconds. Zero TTL indicates that service is removed.
|
||||
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an SRV service resolver.
|
||||
*
|
||||
*/
|
||||
typedef struct otMdnsSrvResolver
|
||||
{
|
||||
const char *mServiceInstance; ///< The service instance label.
|
||||
const char *mServiceType; ///< The service type.
|
||||
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
|
||||
otMdnsSrvCallback mCallback; ///< The callback to report result.
|
||||
} otMdnsSrvResolver;
|
||||
|
||||
/**
|
||||
* Represents an SRV resolver result.
|
||||
*
|
||||
*/
|
||||
struct otMdnsSrvResult
|
||||
{
|
||||
const char *mServiceInstance; ///< The service instance name label.
|
||||
const char *mServiceType; ///< The service type.
|
||||
const char *mHostName; ///< The host name (e.g., "myhost"). Can be NULL when `mTtl` is zero.
|
||||
uint16_t mPort; ///< The service port number.
|
||||
uint16_t mPriority; ///< The service priority.
|
||||
uint16_t mWeight; ///< The service weight.
|
||||
uint32_t mTtl; ///< The service TTL in seconds. Zero TTL indicates SRV record is removed.
|
||||
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a TXT service resolver.
|
||||
*
|
||||
*/
|
||||
typedef struct otMdnsTxtResolver
|
||||
{
|
||||
const char *mServiceInstance; ///< Service instance label.
|
||||
const char *mServiceType; ///< Service type.
|
||||
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
|
||||
otMdnsTxtCallback mCallback;
|
||||
} otMdnsTxtResolver;
|
||||
|
||||
/**
|
||||
* Represents a TXT resolver result.
|
||||
*
|
||||
*/
|
||||
struct otMdnsTxtResult
|
||||
{
|
||||
const char *mServiceInstance; ///< The service instance name label.
|
||||
const char *mServiceType; ///< The service type.
|
||||
const uint8_t *mTxtData; ///< Encoded TXT data bytes. Can be NULL when `mTtl` is zero.
|
||||
uint16_t mTxtDataLength; ///< Length of TXT data.
|
||||
uint32_t mTtl; ///< The TXT data TTL in seconds. Zero TTL indicates record is removed.
|
||||
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an address resolver.
|
||||
*
|
||||
*/
|
||||
typedef struct otMdnsAddressResolver
|
||||
{
|
||||
const char *mHostName; ///< The host name (e.g., "myhost"). MUST NOT contain domain name.
|
||||
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
|
||||
otMdnsAddressCallback mCallback; ///< The callback to report result.
|
||||
} otMdnsAddressResolver;
|
||||
|
||||
/**
|
||||
* Represents a discovered host address and its TTL.
|
||||
*
|
||||
*/
|
||||
typedef struct otMdnsAddressAndTtl
|
||||
{
|
||||
otIp6Address mAddress; ///< The IPv6 address. For IPv4 address the IPv4-mapped IPv6 address format is used.
|
||||
uint32_t mTtl; ///< The TTL in seconds.
|
||||
} otMdnsAddressAndTtl;
|
||||
|
||||
/**
|
||||
* Represents address resolver result.
|
||||
*
|
||||
*/
|
||||
struct otMdnsAddressResult
|
||||
{
|
||||
const char *mHostName; ///< The host name.
|
||||
const otMdnsAddressAndTtl *mAddresses; ///< Array of host addresses and their TTL. Can be NULL if empty.
|
||||
uint16_t mAddressesLength; ///< Number of entries in `mAddresses` array.
|
||||
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts a service browser.
|
||||
*
|
||||
* Initiates a continuous search for the specified `mServiceType` in @p aBrowser. For sub-type services, use
|
||||
* `mSubTypeLabel` to define the sub-type, for base services, set `mSubTypeLabel` to NULL.
|
||||
*
|
||||
* Discovered services are reported through the `mCallback` function in @p aBrowser. Services that have been removed
|
||||
* are reported with a TTL value of zero. The callback may be invoked immediately with cached information (if available)
|
||||
* and potentially before this function returns. When cached results are used, the reported TTL value will reflect
|
||||
* the original TTL from the last received response.
|
||||
*
|
||||
* Multiple browsers can be started for the same service, provided they use different callback functions.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aBrowser The browser to be started.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Browser started successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
* @retval OT_ERROR_ALREADY An identical browser (same service and callback) is already active.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStartBrowser(otInstance *aInstance, const otMdnsBrowser *aBrowser);
|
||||
|
||||
/**
|
||||
* Stops a service browser.
|
||||
*
|
||||
* No action is performed if no matching browser with the same service and callback is currently active.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aBrowser The browser to stop.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Browser stopped successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStopBrowser(otInstance *aInstance, const otMdnsBrowser *aBroswer);
|
||||
|
||||
/**
|
||||
* Starts an SRV record resolver.
|
||||
*
|
||||
* Initiates a continuous SRV record resolver for the specified service in @p aResolver.
|
||||
*
|
||||
* Discovered information is reported through the `mCallback` function in @p aResolver. When the service is removed
|
||||
* it is reported with a TTL value of zero. In this case, `mHostName` may be NULL and other result fields (such as
|
||||
* `mPort`) should be ignored.
|
||||
*
|
||||
* The callback may be invoked immediately with cached information (if available) and potentially before this function
|
||||
* returns. When cached result is used, the reported TTL value will reflect the original TTL from the last received
|
||||
* response.
|
||||
*
|
||||
* Multiple resolvers can be started for the same service, provided they use different callback functions.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResolver The resolver to be started.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Resolver started successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
* @retval OT_ERROR_ALREADY An identical resolver (same service and callback) is already active.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStartSrvResolver(otInstance *aInstance, const otMdnsSrvResolver *aResolver);
|
||||
|
||||
/**
|
||||
* Stops an SRV record resolver.
|
||||
*
|
||||
* No action is performed if no matching resolver with the same service and callback is currently active.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResolver The resolver to stop.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Resolver stopped successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStopSrvResolver(otInstance *aInstance, const otMdnsSrvResolver *aResolver);
|
||||
|
||||
/**
|
||||
* Starts a TXT record resolver.
|
||||
*
|
||||
* Initiates a continuous TXT record resolver for the specified service in @p aResolver.
|
||||
*
|
||||
* Discovered information is reported through the `mCallback` function in @p aResolver. When the TXT record is removed
|
||||
* it is reported with a TTL value of zero. In this case, `mTxtData` may be NULL, and other result fields (such as
|
||||
* `mTxtDataLength`) should be ignored.
|
||||
*
|
||||
* The callback may be invoked immediately with cached information (if available) and potentially before this function
|
||||
* returns. When cached result is used, the reported TTL value will reflect the original TTL from the last received
|
||||
* response.
|
||||
*
|
||||
* Multiple resolvers can be started for the same service, provided they use different callback functions.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResolver The resolver to be started.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Resolver started successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
* @retval OT_ERROR_ALREADY An identical resolver (same service and callback) is already active.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStartTxtResolver(otInstance *aInstance, const otMdnsTxtResolver *aResolver);
|
||||
|
||||
/**
|
||||
* Stops a TXT record resolver.
|
||||
*
|
||||
* No action is performed if no matching resolver with the same service and callback is currently active.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResolver The resolver to stop.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Resolver stopped successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStopTxtResolver(otInstance *aInstance, const otMdnsTxtResolver *aResolver);
|
||||
|
||||
/**
|
||||
* Starts an IPv6 address resolver.
|
||||
*
|
||||
* 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
|
||||
* 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).
|
||||
*
|
||||
* The callback may be invoked immediately with cached information (if available) and potentially before this function
|
||||
* returns. When cached result is used, the reported TTL values will reflect the original TTL from the last received
|
||||
* response.
|
||||
*
|
||||
* Multiple resolvers can be started for the same host name, provided they use different callback functions.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResolver The resolver to be started.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Resolver started successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
* @retval OT_ERROR_ALREADY An identical resolver (same host and callback) is already active.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStartIp6AddressResolver(otInstance *aInstance, const otMdnsAddressResolver *aResolver);
|
||||
|
||||
/**
|
||||
* Stops an IPv6 address resolver.
|
||||
*
|
||||
* No action is performed if no matching resolver with the same host name and callback is currently active.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResolver The resolver to stop.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Resolver stopped successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStopIp6AddressResolver(otInstance *aInstance, const otMdnsAddressResolver *aResolver);
|
||||
|
||||
/**
|
||||
* Starts an IPv4 address resolver.
|
||||
*
|
||||
* 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
|
||||
* 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).
|
||||
*
|
||||
* The callback may be invoked immediately with cached information (if available) and potentially before this function
|
||||
* returns. When cached result is used, the reported TTL values will reflect the original TTL from the last received
|
||||
* response.
|
||||
*
|
||||
* Multiple resolvers can be started for the same host name, provided they use different callback functions.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResolver The resolver to be started.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Resolver started successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
* @retval OT_ERROR_ALREADY An identical resolver (same host and callback) is already active.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStartIp4AddressResolver(otInstance *aInstance, const otMdnsAddressResolver *aResolver);
|
||||
|
||||
/**
|
||||
* Stops an IPv4 address resolver.
|
||||
*
|
||||
* No action is performed if no matching resolver with the same host name and callback is currently active.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aResolver The resolver to stop.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Resolver stopped successfully.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is not enabled.
|
||||
*
|
||||
*/
|
||||
otError otMdnsStopIp4AddressResolver(otInstance *aInstance, const otMdnsAddressResolver *aResolver);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_MULTICAST_DNS_H_
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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
|
||||
* @brief
|
||||
* This file includes the platform abstraction for mDNS socket.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_PLATFORM_MULTICAST_DNS_SOCKET_H_
|
||||
#define OPENTHREAD_PLATFORM_MULTICAST_DNS_SOCKET_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/message.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup plat-mdns
|
||||
*
|
||||
* @brief
|
||||
* This module defines platform APIs for Multicast DNS (mDNS) socket.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a socket address info.
|
||||
*
|
||||
*/
|
||||
typedef struct otPlatMdnsAddressInfo
|
||||
{
|
||||
otIp6Address mAddress; ///< IP address. IPv4-mapped IPv6 format should be used to represent IPv4 address.
|
||||
uint16_t mPort; ///< Port number.
|
||||
uint32_t mInfraIfIndex; ///< Interface index.
|
||||
} otPlatMdnsAddressInfo;
|
||||
|
||||
/**
|
||||
* Enables or disables listening for mDNS messages sent to mDNS port 5353.
|
||||
*
|
||||
* When listening is enabled, the platform MUST listen for multicast messages sent to UDP destination port 5353 at the
|
||||
* mDNS link-local multicast address `224.0.0.251` and its IPv6 equivalent `ff02::fb`.
|
||||
*
|
||||
* The platform SHOULD also listen for any unicast messages sent to UDP destination port 5353. If this is not possible,
|
||||
* then OpenThread mDNS module can be configured to not use any "QU" questions requesting unicast response.
|
||||
*
|
||||
* While enabled, all received messages MUST be reported back using `otPlatMdnsHandleReceive()` callback.
|
||||
*
|
||||
* @param[in] aInstance The OpernThread instance.
|
||||
* @param[in] aEnable Indicate whether to enable or disable.
|
||||
* @param[in] aInfraInfIndex The infrastructure network interface index.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully enabled/disabled listening for mDNS messages.
|
||||
* @retval OT_ERROR_FAILED Failed to enable/disable listening for mDNS messages.
|
||||
*
|
||||
*/
|
||||
otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex);
|
||||
|
||||
/**
|
||||
* Sends an mDNS message as multicast.
|
||||
*
|
||||
* The platform MUST multicast the prepared mDNS message in @p aMessage as a UDP message using the mDNS well-known port
|
||||
* number 5353 for both source and destination ports. The message MUST be sent to the mDNS link-local multicast
|
||||
* address `224.0.0.251` and/or its IPv6 equivalent `ff02::fb`.
|
||||
*
|
||||
* @p aMessage contains the mDNS message starting with DNS header at offset zero. It does not include IP or UDP headers.
|
||||
* This function passes the ownership of @p aMessage to the platform layer and platform implementation MUST free
|
||||
* @p aMessage once sent and no longer needed.
|
||||
*
|
||||
* The platform MUST allow multicast loopback, i.e., the multicast message @p aMessage MUST also be received and
|
||||
* passed back to OpenThread stack using `otPlatMdnsHandleReceive()` callback. This behavior is essential for the
|
||||
* OpenThread mDNS stack to process and potentially respond to its own queries, while allowing other mDNS receivers
|
||||
* to also receive the query and its response.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aMessage The mDNS message to multicast. Ownership is transferred to the platform layer.
|
||||
* @param[in] aInfraIfIndex The infrastructure network interface index.
|
||||
*
|
||||
*/
|
||||
void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex);
|
||||
|
||||
/**
|
||||
* Sends an mDNS message as unicast.
|
||||
*
|
||||
* The platform MUST send the prepared mDNS message in @p aMessage as a UDP message using source UDP port 5353 to
|
||||
* the destination address and port number specified by @p aAddress.
|
||||
*
|
||||
* @p aMessage contains the DNS message starting with the DNS header at offset zero. It does not include IP or UDP
|
||||
* headers. This function passes the ownership of @p aMessage to the platform layer and platform implementation
|
||||
* MUST free @p aMessage once sent and no longer needed.
|
||||
*
|
||||
* The @p aAddress fields are as follows:
|
||||
*
|
||||
* - `mAddress` specifies the destination address. IPv4-mapped IPv6 format is used to represent an IPv4 destination.
|
||||
* - `mPort` specifies the destination port.
|
||||
* - `mInfraIndex` specifies the interface index.
|
||||
*
|
||||
* If the @aAddress matches this devices address, the platform MUST ensure to receive and pass the message back to
|
||||
* the OpenThread stack using `otPlatMdnsHandleReceive()` for processing.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aMessage The mDNS message to multicast. Ownership is transferred to platform layer.
|
||||
* @param[in] aAddress The destination address info.
|
||||
*
|
||||
*/
|
||||
void otPlatMdnsSendUnicast(otInstance *aInstance, otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress);
|
||||
|
||||
/**
|
||||
* Callback to notify OpenThread mDNS module of a received message on UDP port 5353.
|
||||
*
|
||||
* @p aMessage MUST contain DNS message starting with the DNS header at offset zero. This function passes the
|
||||
* ownership of @p aMessage from the platform layer to the OpenThread stack. The OpenThread stack will free the
|
||||
* message once processed.
|
||||
*
|
||||
* The @p aAddress fields are as follows:
|
||||
*
|
||||
* - `mAddress` specifies the sender's address. IPv4-mapped IPv6 format is used to represent an IPv4 destination.
|
||||
* - `mPort` specifies the sender's port.
|
||||
* - `mInfraIndex` specifies the interface index.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aMessage The received mDNS message. Ownership is transferred to the OpenThread stack.
|
||||
* @param[in] aIsUnicast Indicates whether the received message is unicast or multicast.
|
||||
* @param[in] aAddress The sender's address info.
|
||||
*
|
||||
*/
|
||||
extern void otPlatMdnsHandleReceive(otInstance *aInstance,
|
||||
otMessage *aMessage,
|
||||
bool aIsUnicast,
|
||||
const otPlatMdnsAddressInfo *aAddress);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_PLATFORM_MULTICAST_DNS_SOCKET_H_
|
||||
@@ -53,6 +53,8 @@ openthread_cli_sources = [
|
||||
"cli_link_metrics.hpp",
|
||||
"cli_mac_filter.cpp",
|
||||
"cli_mac_filter.hpp",
|
||||
"cli_mdns.cpp",
|
||||
"cli_mdns.hpp",
|
||||
"cli_network_data.cpp",
|
||||
"cli_network_data.hpp",
|
||||
"cli_ping.cpp",
|
||||
|
||||
@@ -44,6 +44,7 @@ set(COMMON_SOURCES
|
||||
cli_joiner.cpp
|
||||
cli_link_metrics.cpp
|
||||
cli_mac_filter.cpp
|
||||
cli_mdns.cpp
|
||||
cli_network_data.cpp
|
||||
cli_ping.cpp
|
||||
cli_srp_client.cpp
|
||||
|
||||
@@ -119,6 +119,9 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi
|
||||
#if OPENTHREAD_CLI_DNS_ENABLE
|
||||
, mDns(aInstance, *this)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
, mMdns(aInstance, *this)
|
||||
#endif
|
||||
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
, mBbr(aInstance, *this)
|
||||
#endif
|
||||
@@ -2763,6 +2766,10 @@ exit:
|
||||
template <> otError Interpreter::Process<Cmd("dns")>(Arg aArgs[]) { return mDns.Process(aArgs); }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
template <> otError Interpreter::Process<Cmd("mdns")>(Arg aArgs[]) { return mMdns.Process(aArgs); }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
void Interpreter::OutputEidCacheEntry(const otCacheEntryInfo &aEntry)
|
||||
{
|
||||
@@ -8579,6 +8586,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
CmdEntry("macfilter"),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
CmdEntry("mdns"),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
|
||||
CmdEntry("meshdiag"),
|
||||
#endif
|
||||
|
||||
@@ -61,12 +61,14 @@
|
||||
#include "cli/cli_bbr.hpp"
|
||||
#include "cli/cli_br.hpp"
|
||||
#include "cli/cli_commissioner.hpp"
|
||||
#include "cli/cli_config.h"
|
||||
#include "cli/cli_dataset.hpp"
|
||||
#include "cli/cli_dns.hpp"
|
||||
#include "cli/cli_history.hpp"
|
||||
#include "cli/cli_joiner.hpp"
|
||||
#include "cli/cli_link_metrics.hpp"
|
||||
#include "cli/cli_mac_filter.hpp"
|
||||
#include "cli/cli_mdns.hpp"
|
||||
#include "cli/cli_network_data.hpp"
|
||||
#include "cli/cli_ping.hpp"
|
||||
#include "cli/cli_srp_client.hpp"
|
||||
@@ -117,6 +119,7 @@ class Interpreter : public OutputImplementer, public Utils
|
||||
friend class Dns;
|
||||
friend class Joiner;
|
||||
friend class LinkMetrics;
|
||||
friend class Mdns;
|
||||
friend class NetworkData;
|
||||
friend class PingSender;
|
||||
friend class SrpClient;
|
||||
@@ -446,6 +449,10 @@ private:
|
||||
Dns mDns;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
Mdns mMdns;
|
||||
#endif
|
||||
|
||||
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
Bbr mBbr;
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,776 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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 implements CLI for mDNS.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "cli_mdns.hpp"
|
||||
|
||||
#include <openthread/nat64.h>
|
||||
#include "cli/cli.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Cli {
|
||||
|
||||
template <> otError Mdns::Process<Cmd("enable")>(Arg aArgs[])
|
||||
{
|
||||
otError error;
|
||||
uint32_t infraIfIndex;
|
||||
|
||||
SuccessOrExit(error = aArgs[0].ParseAsUint32(infraIfIndex));
|
||||
VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(error = otMdnsSetEnabled(GetInstancePtr(), true, infraIfIndex));
|
||||
|
||||
mInfraIfIndex = infraIfIndex;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("disable")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
error = otMdnsSetEnabled(GetInstancePtr(), false, /* aInfraIfIndex */ 0);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("state")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
OutputEnabledDisabledStatus(otMdnsIsEnabled(GetInstancePtr()));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("unicastquestion")>(Arg aArgs[])
|
||||
{
|
||||
return ProcessEnableDisable(aArgs, otMdnsIsQuestionUnicastAllowed, otMdnsSetQuestionUnicastAllowed);
|
||||
}
|
||||
|
||||
void Mdns::OutputHost(const otMdnsHost &aHost)
|
||||
{
|
||||
OutputLine("Host %s", aHost.mHostName);
|
||||
OutputLine(kIndentSize, "%u address:", aHost.mAddressesLength);
|
||||
|
||||
for (uint16_t index = 0; index < aHost.mAddressesLength; index++)
|
||||
{
|
||||
OutputFormat(kIndentSize, " ");
|
||||
OutputIp6AddressLine(aHost.mAddresses[index]);
|
||||
}
|
||||
|
||||
OutputLine(kIndentSize, "ttl: %lu", ToUlong(aHost.mTtl));
|
||||
}
|
||||
|
||||
void Mdns::OutputService(const otMdnsService &aService)
|
||||
{
|
||||
OutputLine("Service %s for %s", aService.mServiceInstance, aService.mServiceType);
|
||||
OutputLine(kIndentSize, "host: %s", aService.mHostName);
|
||||
|
||||
if (aService.mSubTypeLabelsLength > 0)
|
||||
{
|
||||
OutputLine(kIndentSize, "%u sub-type:", aService.mSubTypeLabelsLength);
|
||||
|
||||
for (uint16_t index = 0; index < aService.mSubTypeLabelsLength; index++)
|
||||
{
|
||||
OutputLine(kIndentSize * 2, "%s", aService.mSubTypeLabels[index]);
|
||||
}
|
||||
}
|
||||
|
||||
OutputLine(kIndentSize, "port: %u", aService.mPort);
|
||||
OutputLine(kIndentSize, "priority: %u", aService.mPriority);
|
||||
OutputLine(kIndentSize, "weight: %u", aService.mWeight);
|
||||
OutputLine(kIndentSize, "ttl: %lu", ToUlong(aService.mTtl));
|
||||
|
||||
if ((aService.mTxtData == nullptr) || (aService.mTxtDataLength == 0))
|
||||
{
|
||||
OutputLine(kIndentSize, "txt-data: (empty)");
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputFormat(kIndentSize, "txt-data: ");
|
||||
OutputBytesLine(aService.mTxtData, aService.mTxtDataLength);
|
||||
}
|
||||
}
|
||||
|
||||
void Mdns::OutputKey(const otMdnsKey &aKey)
|
||||
{
|
||||
if (aKey.mServiceType != nullptr)
|
||||
{
|
||||
OutputLine("Key %s for %s (service)", aKey.mName, aKey.mServiceType);
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputLine("Key %s (host)", aKey.mName);
|
||||
}
|
||||
|
||||
OutputFormat(kIndentSize, "key-data: ");
|
||||
OutputBytesLine(aKey.mKeyData, aKey.mKeyDataLength);
|
||||
|
||||
OutputLine(kIndentSize, "ttl: %lu", ToUlong(aKey.mTtl));
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("register")>(Arg aArgs[])
|
||||
{
|
||||
// mdns [async] [host|service|key] <entry specific args>
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
bool isAsync = false;
|
||||
|
||||
if (aArgs[0] == "async")
|
||||
{
|
||||
isAsync = true;
|
||||
aArgs++;
|
||||
}
|
||||
|
||||
if (aArgs[0] == "host")
|
||||
{
|
||||
SuccessOrExit(error = ProcessRegisterHost(aArgs + 1));
|
||||
}
|
||||
else if (aArgs[0] == "service")
|
||||
{
|
||||
SuccessOrExit(error = ProcessRegisterService(aArgs + 1));
|
||||
}
|
||||
else if (aArgs[0] == "key")
|
||||
{
|
||||
SuccessOrExit(error = ProcessRegisterKey(aArgs + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
if (isAsync)
|
||||
{
|
||||
OutputLine("mDNS request id: %lu", ToUlong(mRequestId));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_PENDING;
|
||||
mWaitingForCallback = true;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Mdns::ProcessRegisterHost(Arg aArgs[])
|
||||
{
|
||||
// register host <name> [<zero or more addresses>] [<ttl>]
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
otMdnsHost host;
|
||||
otIp6Address addresses[kMaxAddresses];
|
||||
|
||||
memset(&host, 0, sizeof(host));
|
||||
|
||||
VerifyOrExit(!aArgs->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
host.mHostName = aArgs->GetCString();
|
||||
aArgs++;
|
||||
|
||||
host.mAddresses = addresses;
|
||||
|
||||
for (; !aArgs->IsEmpty(); aArgs++)
|
||||
{
|
||||
otIp6Address address;
|
||||
uint32_t ttl;
|
||||
|
||||
if (aArgs->ParseAsIp6Address(address) == OT_ERROR_NONE)
|
||||
{
|
||||
VerifyOrExit(host.mAddressesLength < kMaxAddresses, error = OT_ERROR_NO_BUFS);
|
||||
addresses[host.mAddressesLength] = address;
|
||||
host.mAddressesLength++;
|
||||
}
|
||||
else if (aArgs->ParseAsUint32(ttl) == OT_ERROR_NONE)
|
||||
{
|
||||
host.mTtl = ttl;
|
||||
VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
}
|
||||
|
||||
OutputHost(host);
|
||||
|
||||
mRequestId++;
|
||||
error = otMdnsRegisterHost(GetInstancePtr(), &host, mRequestId, HandleRegisterationDone);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Mdns::ProcessRegisterService(Arg aArgs[])
|
||||
{
|
||||
otError error;
|
||||
otMdnsService service;
|
||||
Buffers buffers;
|
||||
|
||||
SuccessOrExit(error = ParseServiceArgs(aArgs, service, buffers));
|
||||
|
||||
OutputService(service);
|
||||
|
||||
mRequestId++;
|
||||
error = otMdnsRegisterService(GetInstancePtr(), &service, mRequestId, HandleRegisterationDone);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Mdns::ParseServiceArgs(Arg aArgs[], otMdnsService &aService, Buffers &aBuffers)
|
||||
{
|
||||
// mdns register service <instance-label> <service-type,sub_types> <host-name> <port> [<prio>] [<weight>] [<ttl>]
|
||||
// [<txtdata>]
|
||||
|
||||
otError error = OT_ERROR_INVALID_ARGS;
|
||||
char *label;
|
||||
uint16_t len;
|
||||
|
||||
memset(&aService, 0, sizeof(aService));
|
||||
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
aService.mServiceInstance = aArgs->GetCString();
|
||||
aArgs++;
|
||||
|
||||
// Copy service type into `aBuffer.mString`, then search for
|
||||
// `,` in the string to parse the list of sub-types (if any).
|
||||
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
len = aArgs->GetLength();
|
||||
VerifyOrExit(len + 1 < kStringSize, error = OT_ERROR_NO_BUFS);
|
||||
memcpy(aBuffers.mString, aArgs->GetCString(), len + 1);
|
||||
|
||||
aService.mServiceType = aBuffers.mString;
|
||||
aService.mSubTypeLabels = aBuffers.mSubTypeLabels;
|
||||
|
||||
label = strchr(aBuffers.mString, ',');
|
||||
|
||||
if (label != nullptr)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
*label++ = '\0';
|
||||
|
||||
VerifyOrExit(aService.mSubTypeLabelsLength < kMaxSubTypes, error = OT_ERROR_NO_BUFS);
|
||||
aBuffers.mSubTypeLabels[aService.mSubTypeLabelsLength] = label;
|
||||
aService.mSubTypeLabelsLength++;
|
||||
|
||||
label = strchr(label, ',');
|
||||
|
||||
if (label == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aArgs++;
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
aService.mHostName = aArgs->GetCString();
|
||||
|
||||
aArgs++;
|
||||
SuccessOrExit(aArgs->ParseAsUint16(aService.mPort));
|
||||
|
||||
// The rest of `Args` are optional.
|
||||
|
||||
error = OT_ERROR_NONE;
|
||||
|
||||
aArgs++;
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
SuccessOrExit(error = aArgs->ParseAsUint16(aService.mPriority));
|
||||
|
||||
aArgs++;
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
SuccessOrExit(error = aArgs->ParseAsUint16(aService.mWeight));
|
||||
|
||||
aArgs++;
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
SuccessOrExit(error = aArgs->ParseAsUint32(aService.mTtl));
|
||||
|
||||
aArgs++;
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
len = kMaxTxtDataSize;
|
||||
SuccessOrExit(error = aArgs->ParseAsHexString(len, aBuffers.mTxtData));
|
||||
aService.mTxtData = aBuffers.mTxtData;
|
||||
aService.mTxtDataLength = len;
|
||||
|
||||
aArgs++;
|
||||
VerifyOrExit(aArgs->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Mdns::ProcessRegisterKey(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_INVALID_ARGS;
|
||||
otMdnsKey key;
|
||||
uint16_t len;
|
||||
uint8_t data[kMaxKeyDataSize];
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
key.mName = aArgs->GetCString();
|
||||
|
||||
aArgs++;
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
|
||||
if (aArgs->GetCString()[0] == '_')
|
||||
{
|
||||
key.mServiceType = aArgs->GetCString();
|
||||
aArgs++;
|
||||
VerifyOrExit(!aArgs->IsEmpty());
|
||||
}
|
||||
|
||||
len = kMaxKeyDataSize;
|
||||
SuccessOrExit(error = aArgs->ParseAsHexString(len, data));
|
||||
|
||||
key.mKeyData = data;
|
||||
key.mKeyDataLength = len;
|
||||
|
||||
// ttl is optional
|
||||
|
||||
aArgs++;
|
||||
|
||||
if (!aArgs->IsEmpty())
|
||||
{
|
||||
SuccessOrExit(error = aArgs->ParseAsUint32(key.mTtl));
|
||||
aArgs++;
|
||||
VerifyOrExit(aArgs->IsEmpty(), error = kErrorInvalidArgs);
|
||||
}
|
||||
|
||||
OutputKey(key);
|
||||
|
||||
mRequestId++;
|
||||
error = otMdnsRegisterKey(GetInstancePtr(), &key, mRequestId, HandleRegisterationDone);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mdns::HandleRegisterationDone(otInstance *aInstance, otMdnsRequestId aRequestId, otError aError)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
Interpreter::GetInterpreter().mMdns.HandleRegisterationDone(aRequestId, aError);
|
||||
}
|
||||
|
||||
void Mdns::HandleRegisterationDone(otMdnsRequestId aRequestId, otError aError)
|
||||
{
|
||||
if (mWaitingForCallback && (aRequestId == mRequestId))
|
||||
{
|
||||
mWaitingForCallback = false;
|
||||
Interpreter::GetInterpreter().OutputResult(aError);
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputLine("mDNS registration for request id %lu outcome: %s", ToUlong(aRequestId),
|
||||
otThreadErrorToString(aError));
|
||||
}
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("unregister")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_INVALID_ARGS;
|
||||
|
||||
if (aArgs[0] == "host")
|
||||
{
|
||||
otMdnsHost host;
|
||||
|
||||
memset(&host, 0, sizeof(host));
|
||||
VerifyOrExit(!aArgs[1].IsEmpty());
|
||||
host.mHostName = aArgs[1].GetCString();
|
||||
VerifyOrExit(aArgs[2].IsEmpty());
|
||||
|
||||
error = otMdnsUnregisterHost(GetInstancePtr(), &host);
|
||||
}
|
||||
else if (aArgs[0] == "service")
|
||||
{
|
||||
otMdnsService service;
|
||||
|
||||
memset(&service, 0, sizeof(service));
|
||||
VerifyOrExit(!aArgs[1].IsEmpty());
|
||||
service.mServiceInstance = aArgs[1].GetCString();
|
||||
VerifyOrExit(!aArgs[2].IsEmpty());
|
||||
service.mServiceType = aArgs[2].GetCString();
|
||||
VerifyOrExit(aArgs[3].IsEmpty());
|
||||
|
||||
error = otMdnsUnregisterService(GetInstancePtr(), &service);
|
||||
}
|
||||
else if (aArgs[0] == "key")
|
||||
{
|
||||
otMdnsKey key;
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
VerifyOrExit(!aArgs[1].IsEmpty());
|
||||
key.mName = aArgs[1].GetCString();
|
||||
|
||||
if (!aArgs[2].IsEmpty())
|
||||
{
|
||||
key.mServiceType = aArgs[2].GetCString();
|
||||
VerifyOrExit(aArgs[3].IsEmpty());
|
||||
}
|
||||
|
||||
error = otMdnsUnregisterKey(GetInstancePtr(), &key);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Mdns::ParseStartOrStop(const Arg &aArg, bool &aIsStart)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
if (aArg == "start")
|
||||
{
|
||||
aIsStart = true;
|
||||
}
|
||||
else if (aArg == "stop")
|
||||
{
|
||||
aIsStart = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("browser")>(Arg aArgs[])
|
||||
{
|
||||
// mdns browser start|stop <service-type> [<sub-type>]
|
||||
|
||||
otError error;
|
||||
otMdnsBrowser browser;
|
||||
bool isStart;
|
||||
|
||||
ClearAllBytes(browser);
|
||||
|
||||
SuccessOrExit(error = ParseStartOrStop(aArgs[0], isStart));
|
||||
VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
browser.mServiceType = aArgs[1].GetCString();
|
||||
|
||||
if (!aArgs[2].IsEmpty())
|
||||
{
|
||||
browser.mSubTypeLabel = aArgs[2].GetCString();
|
||||
VerifyOrExit(aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
browser.mInfraIfIndex = mInfraIfIndex;
|
||||
browser.mCallback = HandleBrowseResult;
|
||||
|
||||
if (isStart)
|
||||
{
|
||||
error = otMdnsStartBrowser(GetInstancePtr(), &browser);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = otMdnsStopBrowser(GetInstancePtr(), &browser);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mdns::HandleBrowseResult(otInstance *aInstance, const otMdnsBrowseResult *aResult)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
Interpreter::GetInterpreter().mMdns.HandleBrowseResult(*aResult);
|
||||
}
|
||||
|
||||
void Mdns::HandleBrowseResult(const otMdnsBrowseResult &aResult)
|
||||
{
|
||||
OutputFormat("mDNS browse result for %s", aResult.mServiceType);
|
||||
|
||||
if (aResult.mSubTypeLabel)
|
||||
{
|
||||
OutputLine(" sub-type %s", aResult.mSubTypeLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputNewLine();
|
||||
}
|
||||
|
||||
OutputLine(kIndentSize, "instance: %s", aResult.mServiceInstance);
|
||||
OutputLine(kIndentSize, "ttl: %lu", ToUlong(aResult.mTtl));
|
||||
OutputLine(kIndentSize, "if-index: %lu", ToUlong(aResult.mInfraIfIndex));
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("srvresolver")>(Arg aArgs[])
|
||||
{
|
||||
// mdns srvresolver start|stop <service-instance> <service-type>
|
||||
|
||||
otError error;
|
||||
otMdnsSrvResolver resolver;
|
||||
bool isStart;
|
||||
|
||||
ClearAllBytes(resolver);
|
||||
|
||||
SuccessOrExit(error = ParseStartOrStop(aArgs[0], isStart));
|
||||
VerifyOrExit(!aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
resolver.mServiceInstance = aArgs[1].GetCString();
|
||||
resolver.mServiceType = aArgs[2].GetCString();
|
||||
resolver.mInfraIfIndex = mInfraIfIndex;
|
||||
resolver.mCallback = HandleSrvResult;
|
||||
|
||||
if (isStart)
|
||||
{
|
||||
error = otMdnsStartSrvResolver(GetInstancePtr(), &resolver);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = otMdnsStopSrvResolver(GetInstancePtr(), &resolver);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mdns::HandleSrvResult(otInstance *aInstance, const otMdnsSrvResult *aResult)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
Interpreter::GetInterpreter().mMdns.HandleSrvResult(*aResult);
|
||||
}
|
||||
|
||||
void Mdns::HandleSrvResult(const otMdnsSrvResult &aResult)
|
||||
{
|
||||
OutputLine("mDNS SRV result for %s for %s", aResult.mServiceInstance, aResult.mServiceType);
|
||||
|
||||
if (aResult.mTtl != 0)
|
||||
{
|
||||
OutputLine(kIndentSize, "host: %s", aResult.mHostName);
|
||||
OutputLine(kIndentSize, "port: %u", aResult.mPort);
|
||||
OutputLine(kIndentSize, "priority: %u", aResult.mPriority);
|
||||
OutputLine(kIndentSize, "weight: %u", aResult.mWeight);
|
||||
}
|
||||
|
||||
OutputLine(kIndentSize, "ttl: %lu", ToUlong(aResult.mTtl));
|
||||
OutputLine(kIndentSize, "if-index: %lu", ToUlong(aResult.mInfraIfIndex));
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("txtresolver")>(Arg aArgs[])
|
||||
{
|
||||
// mdns txtresolver start|stop <service-instance> <service-type>
|
||||
|
||||
otError error;
|
||||
otMdnsTxtResolver resolver;
|
||||
bool isStart;
|
||||
|
||||
ClearAllBytes(resolver);
|
||||
|
||||
SuccessOrExit(error = ParseStartOrStop(aArgs[0], isStart));
|
||||
VerifyOrExit(!aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
resolver.mServiceInstance = aArgs[1].GetCString();
|
||||
resolver.mServiceType = aArgs[2].GetCString();
|
||||
resolver.mInfraIfIndex = mInfraIfIndex;
|
||||
resolver.mCallback = HandleTxtResult;
|
||||
|
||||
if (isStart)
|
||||
{
|
||||
error = otMdnsStartTxtResolver(GetInstancePtr(), &resolver);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = otMdnsStopTxtResolver(GetInstancePtr(), &resolver);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mdns::HandleTxtResult(otInstance *aInstance, const otMdnsTxtResult *aResult)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
Interpreter::GetInterpreter().mMdns.HandleTxtResult(*aResult);
|
||||
}
|
||||
|
||||
void Mdns::HandleTxtResult(const otMdnsTxtResult &aResult)
|
||||
{
|
||||
OutputLine("mDNS TXT result for %s for %s", aResult.mServiceInstance, aResult.mServiceType);
|
||||
|
||||
if (aResult.mTtl != 0)
|
||||
{
|
||||
OutputFormat(kIndentSize, "txt-data: ");
|
||||
OutputBytesLine(aResult.mTxtData, aResult.mTxtDataLength);
|
||||
}
|
||||
|
||||
OutputLine(kIndentSize, "ttl: %lu", ToUlong(aResult.mTtl));
|
||||
OutputLine(kIndentSize, "if-index: %lu", ToUlong(aResult.mInfraIfIndex));
|
||||
}
|
||||
template <> otError Mdns::Process<Cmd("ip6resolver")>(Arg aArgs[])
|
||||
{
|
||||
// mdns ip6resolver start|stop <host-name>
|
||||
|
||||
otError error;
|
||||
otMdnsAddressResolver resolver;
|
||||
bool isStart;
|
||||
|
||||
ClearAllBytes(resolver);
|
||||
|
||||
SuccessOrExit(error = ParseStartOrStop(aArgs[0], isStart));
|
||||
VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
resolver.mHostName = aArgs[1].GetCString();
|
||||
resolver.mInfraIfIndex = mInfraIfIndex;
|
||||
resolver.mCallback = HandleIp6AddressResult;
|
||||
|
||||
if (isStart)
|
||||
{
|
||||
error = otMdnsStartIp6AddressResolver(GetInstancePtr(), &resolver);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = otMdnsStopIp6AddressResolver(GetInstancePtr(), &resolver);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mdns::HandleIp6AddressResult(otInstance *aInstance, const otMdnsAddressResult *aResult)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
Interpreter::GetInterpreter().mMdns.HandleAddressResult(*aResult, kIp6Address);
|
||||
}
|
||||
|
||||
void Mdns::HandleAddressResult(const otMdnsAddressResult &aResult, IpAddressType aType)
|
||||
{
|
||||
OutputLine("mDNS %s address result for %s", aType == kIp6Address ? "IPv6" : "IPv4", aResult.mHostName);
|
||||
|
||||
OutputLine(kIndentSize, "%u address:", aResult.mAddressesLength);
|
||||
|
||||
for (uint16_t index = 0; index < aResult.mAddressesLength; index++)
|
||||
{
|
||||
OutputFormat(kIndentSize, " ");
|
||||
OutputIp6Address(aResult.mAddresses[index].mAddress);
|
||||
OutputLine(" ttl:%lu", ToUlong(aResult.mAddresses[index].mTtl));
|
||||
}
|
||||
|
||||
OutputLine(kIndentSize, "if-index: %lu", ToUlong(aResult.mInfraIfIndex));
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("ip4resolver")>(Arg aArgs[])
|
||||
{
|
||||
// mdns ip4resolver start|stop <host-name>
|
||||
|
||||
otError error;
|
||||
otMdnsAddressResolver resolver;
|
||||
bool isStart;
|
||||
|
||||
ClearAllBytes(resolver);
|
||||
|
||||
SuccessOrExit(error = ParseStartOrStop(aArgs[0], isStart));
|
||||
VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
resolver.mHostName = aArgs[1].GetCString();
|
||||
resolver.mInfraIfIndex = mInfraIfIndex;
|
||||
resolver.mCallback = HandleIp4AddressResult;
|
||||
|
||||
if (isStart)
|
||||
{
|
||||
error = otMdnsStartIp4AddressResolver(GetInstancePtr(), &resolver);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = otMdnsStopIp4AddressResolver(GetInstancePtr(), &resolver);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mdns::HandleIp4AddressResult(otInstance *aInstance, const otMdnsAddressResult *aResult)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
Interpreter::GetInterpreter().mMdns.HandleAddressResult(*aResult, kIp4Address);
|
||||
}
|
||||
|
||||
otError Mdns::Process(Arg aArgs[])
|
||||
{
|
||||
#define CmdEntry(aCommandString) \
|
||||
{ \
|
||||
aCommandString, &Mdns::Process<Cmd(aCommandString)> \
|
||||
}
|
||||
|
||||
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"),
|
||||
};
|
||||
|
||||
#undef CmdEntry
|
||||
|
||||
static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
|
||||
|
||||
otError error = OT_ERROR_INVALID_COMMAND;
|
||||
const Command *command;
|
||||
|
||||
if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
|
||||
{
|
||||
OutputCommandTable(kCommands);
|
||||
ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE);
|
||||
}
|
||||
|
||||
command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
|
||||
VerifyOrExit(command != nullptr);
|
||||
|
||||
error = (this->*command->mHandler)(aArgs + 1);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Cli
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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 contains definitions for CLI to DNS (client and resolver).
|
||||
*/
|
||||
|
||||
#ifndef CLI_MDNS_HPP_
|
||||
#define CLI_MDNS_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/mdns.h>
|
||||
|
||||
#include "cli/cli_config.h"
|
||||
#include "cli/cli_utils.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Cli {
|
||||
|
||||
/**
|
||||
* Implements the mDNS CLI interpreter.
|
||||
*
|
||||
*/
|
||||
class Mdns : private Utils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread Instance.
|
||||
* @param[in] aOutputImplementer An `OutputImplementer`.
|
||||
*
|
||||
*/
|
||||
Mdns(otInstance *aInstance, OutputImplementer &aOutputImplementer)
|
||||
: Utils(aInstance, aOutputImplementer)
|
||||
, mInfraIfIndex(0)
|
||||
, mRequestId(0)
|
||||
, mWaitingForCallback(false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a CLI sub-command.
|
||||
*
|
||||
* @param[in] aArgs An array of command line arguments.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully executed the CLI command.
|
||||
* @retval OT_ERROR_PENDING The CLI command was successfully started but final result is pending.
|
||||
* @retval OT_ERROR_INVALID_COMMAND Invalid or unknown CLI command.
|
||||
* @retval OT_ERROR_INVALID_ARGS Invalid arguments.
|
||||
* @retval ... Error during execution of the CLI command.
|
||||
*
|
||||
*/
|
||||
otError Process(Arg aArgs[]);
|
||||
|
||||
private:
|
||||
using Command = CommandEntry<Mdns>;
|
||||
|
||||
static constexpr uint8_t kIndentSize = 4;
|
||||
static constexpr uint16_t kMaxAddresses = 16;
|
||||
static constexpr uint16_t kStringSize = 400;
|
||||
static constexpr uint16_t kMaxSubTypes = 8;
|
||||
static constexpr uint16_t kMaxTxtDataSize = 200;
|
||||
static constexpr uint16_t kMaxKeyDataSize = 200;
|
||||
|
||||
enum IpAddressType : uint8_t
|
||||
{
|
||||
kIp6Address,
|
||||
kIp4Address,
|
||||
};
|
||||
|
||||
struct Buffers // Used to populate `otMdnsService` field
|
||||
{
|
||||
char mString[kStringSize];
|
||||
const char *mSubTypeLabels[kMaxSubTypes];
|
||||
uint8_t mTxtData[kMaxTxtDataSize];
|
||||
};
|
||||
|
||||
template <CommandId kCommandId> otError Process(Arg aArgs[]);
|
||||
|
||||
void OutputHost(const otMdnsHost &aHost);
|
||||
void OutputService(const otMdnsService &aService);
|
||||
void OutputKey(const otMdnsKey &aKey);
|
||||
otError ProcessRegisterHost(Arg aArgs[]);
|
||||
otError ProcessRegisterService(Arg aArgs[]);
|
||||
otError ProcessRegisterKey(Arg aArgs[]);
|
||||
void HandleRegisterationDone(otMdnsRequestId aRequestId, otError aError);
|
||||
void HandleBrowseResult(const otMdnsBrowseResult &aResult);
|
||||
void HandleSrvResult(const otMdnsSrvResult &aResult);
|
||||
void HandleTxtResult(const otMdnsTxtResult &aResult);
|
||||
void HandleAddressResult(const otMdnsAddressResult &aResult, IpAddressType aType);
|
||||
|
||||
static otError ParseStartOrStop(const Arg &aArg, bool &aIsStart);
|
||||
static void HandleRegisterationDone(otInstance *aInstance, otMdnsRequestId aRequestId, otError aError);
|
||||
static void HandleBrowseResult(otInstance *aInstance, const otMdnsBrowseResult *aResult);
|
||||
static void HandleSrvResult(otInstance *aInstance, const otMdnsSrvResult *aResult);
|
||||
static void HandleTxtResult(otInstance *aInstance, const otMdnsTxtResult *aResult);
|
||||
static void HandleIp6AddressResult(otInstance *aInstance, const otMdnsAddressResult *aResult);
|
||||
static void HandleIp4AddressResult(otInstance *aInstance, const otMdnsAddressResult *aResult);
|
||||
|
||||
static otError ParseServiceArgs(Arg aArgs[], otMdnsService &aService, Buffers &aBuffers);
|
||||
|
||||
uint32_t mInfraIfIndex;
|
||||
otMdnsRequestId mRequestId;
|
||||
bool mWaitingForCallback;
|
||||
};
|
||||
|
||||
} // namespace Cli
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
|
||||
#endif // CLI_MDNS_HPP_
|
||||
@@ -336,6 +336,7 @@ openthread_core_files = [
|
||||
"api/link_metrics_api.cpp",
|
||||
"api/link_raw_api.cpp",
|
||||
"api/logging_api.cpp",
|
||||
"api/mdns_api.cpp",
|
||||
"api/mesh_diag_api.cpp",
|
||||
"api/message_api.cpp",
|
||||
"api/multi_radio_api.cpp",
|
||||
@@ -575,6 +576,8 @@ openthread_core_files = [
|
||||
"net/ip6_mpl.cpp",
|
||||
"net/ip6_mpl.hpp",
|
||||
"net/ip6_types.hpp",
|
||||
"net/mdns.cpp",
|
||||
"net/mdns.hpp",
|
||||
"net/nat64_translator.cpp",
|
||||
"net/nat64_translator.hpp",
|
||||
"net/nd6.cpp",
|
||||
@@ -815,6 +818,7 @@ source_set("libopenthread_core_config") {
|
||||
"config/link_raw.h",
|
||||
"config/logging.h",
|
||||
"config/mac.h",
|
||||
"config/mdns.h",
|
||||
"config/mesh_diag.h",
|
||||
"config/mesh_forwarder.h",
|
||||
"config/misc.h",
|
||||
|
||||
@@ -62,6 +62,7 @@ set(COMMON_SOURCES
|
||||
api/link_metrics_api.cpp
|
||||
api/link_raw_api.cpp
|
||||
api/logging_api.cpp
|
||||
api/mdns_api.cpp
|
||||
api/mesh_diag_api.cpp
|
||||
api/message_api.cpp
|
||||
api/multi_radio_api.cpp
|
||||
@@ -178,6 +179,7 @@ set(COMMON_SOURCES
|
||||
net/ip6_filter.cpp
|
||||
net/ip6_headers.cpp
|
||||
net/ip6_mpl.cpp
|
||||
net/mdns.cpp
|
||||
net/nat64_translator.cpp
|
||||
net/nd6.cpp
|
||||
net/nd_agent.cpp
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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 implements the OpenThread mDNS API.
|
||||
*/
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/mdns.h>
|
||||
|
||||
#include "instance/instance.hpp"
|
||||
#include "net/mdns.hpp"
|
||||
|
||||
using namespace ot;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
|
||||
otError otMdnsSetEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().SetEnabled(aEnable, aInfraIfIndex);
|
||||
}
|
||||
|
||||
bool otMdnsIsEnabled(otInstance *aInstance) { return AsCoreType(aInstance).Get<Dns::Multicast::Core>().IsEnabled(); }
|
||||
|
||||
void otMdnsSetQuestionUnicastAllowed(otInstance *aInstance, bool aAllow)
|
||||
{
|
||||
AsCoreType(aInstance).Get<Dns::Multicast::Core>().SetQuestionUnicastAllowed(aAllow);
|
||||
}
|
||||
|
||||
bool otMdnsIsQuestionUnicastAllowed(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().IsQuestionUnicastAllowed();
|
||||
}
|
||||
|
||||
void otMdnsSetConflictCallback(otInstance *aInstance, otMdnsConflictCallback aCallback)
|
||||
{
|
||||
AsCoreType(aInstance).Get<Dns::Multicast::Core>().SetConflictCallback(aCallback);
|
||||
}
|
||||
|
||||
otError otMdnsRegisterHost(otInstance *aInstance,
|
||||
const otMdnsHost *aHost,
|
||||
otMdnsRequestId aRequestId,
|
||||
otMdnsRegisterCallback aCallback)
|
||||
{
|
||||
AssertPointerIsNotNull(aHost);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().RegisterHost(*aHost, aRequestId, aCallback);
|
||||
}
|
||||
|
||||
otError otMdnsUnregisterHost(otInstance *aInstance, const otMdnsHost *aHost)
|
||||
{
|
||||
AssertPointerIsNotNull(aHost);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().UnregisterHost(*aHost);
|
||||
}
|
||||
|
||||
otError otMdnsRegisterService(otInstance *aInstance,
|
||||
const otMdnsService *aService,
|
||||
otMdnsRequestId aRequestId,
|
||||
otMdnsRegisterCallback aCallback)
|
||||
{
|
||||
AssertPointerIsNotNull(aService);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().RegisterService(*aService, aRequestId, aCallback);
|
||||
}
|
||||
|
||||
otError otMdnsUnregisterService(otInstance *aInstance, const otMdnsService *aService)
|
||||
{
|
||||
AssertPointerIsNotNull(aService);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().UnregisterService(*aService);
|
||||
}
|
||||
|
||||
otError otMdnsRegisterKey(otInstance *aInstance,
|
||||
const otMdnsKey *aKey,
|
||||
otMdnsRequestId aRequestId,
|
||||
otMdnsRegisterCallback aCallback)
|
||||
{
|
||||
AssertPointerIsNotNull(aKey);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().RegisterKey(*aKey, aRequestId, aCallback);
|
||||
}
|
||||
|
||||
otError otMdnsUnregisterKey(otInstance *aInstance, const otMdnsKey *aKey)
|
||||
{
|
||||
AssertPointerIsNotNull(aKey);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().UnregisterKey(*aKey);
|
||||
}
|
||||
|
||||
otError otMdnsStartBrowser(otInstance *aInstance, const otMdnsBrowser *aBroswer)
|
||||
{
|
||||
AssertPointerIsNotNull(aBroswer);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StartBrowser(*aBroswer);
|
||||
}
|
||||
|
||||
otError otMdnsStopBrowser(otInstance *aInstance, const otMdnsBrowser *aBroswer)
|
||||
{
|
||||
AssertPointerIsNotNull(aBroswer);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StopBrowser(*aBroswer);
|
||||
}
|
||||
|
||||
otError otMdnsStartSrvResolver(otInstance *aInstance, const otMdnsSrvResolver *aResolver)
|
||||
{
|
||||
AssertPointerIsNotNull(aResolver);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StartSrvResolver(*aResolver);
|
||||
}
|
||||
|
||||
otError otMdnsStopSrvResolver(otInstance *aInstance, const otMdnsSrvResolver *aResolver)
|
||||
{
|
||||
AssertPointerIsNotNull(aResolver);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StopSrvResolver(*aResolver);
|
||||
}
|
||||
|
||||
otError otMdnsStartTxtResolver(otInstance *aInstance, const otMdnsTxtResolver *aResolver)
|
||||
{
|
||||
AssertPointerIsNotNull(aResolver);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StartTxtResolver(*aResolver);
|
||||
}
|
||||
|
||||
otError otMdnsStopTxtResolver(otInstance *aInstance, const otMdnsTxtResolver *aResolver)
|
||||
{
|
||||
AssertPointerIsNotNull(aResolver);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StopTxtResolver(*aResolver);
|
||||
}
|
||||
|
||||
otError otMdnsStartIp6AddressResolver(otInstance *aInstance, const otMdnsAddressResolver *aResolver)
|
||||
{
|
||||
AssertPointerIsNotNull(aResolver);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StartIp6AddressResolver(*aResolver);
|
||||
}
|
||||
|
||||
otError otMdnsStopIp6AddressResolver(otInstance *aInstance, const otMdnsAddressResolver *aResolver)
|
||||
{
|
||||
AssertPointerIsNotNull(aResolver);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StopIp6AddressResolver(*aResolver);
|
||||
}
|
||||
|
||||
otError otMdnsStartIp4AddressResolver(otInstance *aInstance, const otMdnsAddressResolver *aResolver)
|
||||
{
|
||||
AssertPointerIsNotNull(aResolver);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StartIp4AddressResolver(*aResolver);
|
||||
}
|
||||
|
||||
otError otMdnsStopIp4AddressResolver(otInstance *aInstance, const otMdnsAddressResolver *aResolver)
|
||||
{
|
||||
AssertPointerIsNotNull(aResolver);
|
||||
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().StopIp4AddressResolver(*aResolver);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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 compile-time configurations for the Multicast DNS (mDNS).
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_MULTICAST_DNS_H_
|
||||
#define CONFIG_MULTICAST_DNS_H_
|
||||
|
||||
/**
|
||||
* @addtogroup config-mdns
|
||||
*
|
||||
* @brief
|
||||
* This module includes configuration variables for the Multicast DNS (mDNS).
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
*
|
||||
* Define to 1 to enable Multicast DNS (mDNS) support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
*
|
||||
* Define to 1 to allow public OpenThread APIs to be defined for Multicast DNS (mDNS) module.
|
||||
*
|
||||
* The OpenThread mDNS module is mainly intended for use by other OT core modules, so the public APIs are by default
|
||||
* not provided.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MULTICAST_DNS_DEFAULT_QUESTION_UNICAST_ALLOWED
|
||||
*
|
||||
* Specified the default value for `otMdnsIsQuestionUnicastAllowed()` which indicates whether mDNS core is allowed to
|
||||
* send "QU" questions (questions requesting unicast response). When allowed, the first probe will be sent as "QU"
|
||||
* question. The `otMdnsSetQuestionUnicastAllowed()` can be used to change the default value at run-time.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MULTICAST_DNS_DEFAULT_QUESTION_UNICAST_ALLOWED
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_DEFAULT_QUESTION_UNICAST_ALLOWED 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MULTICAST_DNS_MOCK_PLAT_APIS_ENABLE
|
||||
*
|
||||
* Define to 1 to add mock (empty) implementation of mDNS platform APIs.
|
||||
*
|
||||
* This is intended for generating code size report only and should not be used otherwise.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MULTICAST_DNS_MOCK_PLAT_APIS_ENABLE
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_MOCK_PLAT_APIS_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#endif // CONFIG_MULTICAST_DNS_H_
|
||||
@@ -122,6 +122,9 @@ Instance::Instance(void)
|
||||
#if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
, mDnsDso(*this)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
, mMdnsCore(*this)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
|
||||
, mSntpClient(*this)
|
||||
#endif
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
#include "net/dnssd_server.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
#include "net/ip6_filter.hpp"
|
||||
#include "net/mdns.hpp"
|
||||
#include "net/nat64_translator.hpp"
|
||||
#include "net/nd_agent.hpp"
|
||||
#include "net/netif.hpp"
|
||||
@@ -526,6 +527,10 @@ private:
|
||||
Dns::Dso mDnsDso;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
Dns::Multicast::Core mMdnsCore;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
|
||||
Sntp::Client mSntpClient;
|
||||
#endif
|
||||
@@ -925,6 +930,10 @@ template <> inline Dns::ServiceDiscovery::Server &Instance::Get(void) { return m
|
||||
template <> inline Dns::Dso &Instance::Get(void) { return mDnsDso; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
template <> inline Dns::Multicast::Core &Instance::Get(void) { return mMdnsCore; }
|
||||
#endif
|
||||
|
||||
template <> inline NetworkDiagnostic::Server &Instance::Get(void) { return mNetworkDiagnosticServer; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/num_utils.hpp"
|
||||
#include "common/numeric_limits.hpp"
|
||||
#include "common/random.hpp"
|
||||
#include "common/string.hpp"
|
||||
#include "instance/instance.hpp"
|
||||
@@ -1343,5 +1344,35 @@ exit:
|
||||
return valid;
|
||||
}
|
||||
|
||||
void NsecRecord::TypeBitMap::AddType(uint16_t aType)
|
||||
{
|
||||
if ((aType >> 8) == mBlockNumber)
|
||||
{
|
||||
uint8_t type = static_cast<uint8_t>(aType & 0xff);
|
||||
uint8_t index = (type / kBitsPerByte);
|
||||
uint16_t mask = (0x80 >> (type % kBitsPerByte));
|
||||
|
||||
mBitmaps[index] |= mask;
|
||||
mBitmapLength = Max<uint8_t>(mBitmapLength, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool NsecRecord::TypeBitMap::ContainsType(uint16_t aType) const
|
||||
{
|
||||
bool contains = false;
|
||||
uint8_t type = static_cast<uint8_t>(aType & 0xff);
|
||||
uint8_t index = (type / kBitsPerByte);
|
||||
uint16_t mask = (0x80 >> (type % kBitsPerByte));
|
||||
|
||||
VerifyOrExit((aType >> 8) == mBlockNumber);
|
||||
|
||||
VerifyOrExit(index < mBitmapLength);
|
||||
|
||||
contains = (mBitmaps[index] & mask);
|
||||
|
||||
exit:
|
||||
return contains;
|
||||
}
|
||||
|
||||
} // namespace Dns
|
||||
} // namespace ot
|
||||
|
||||
@@ -1336,6 +1336,7 @@ public:
|
||||
static constexpr uint16_t kTypeAaaa = 28; ///< IPv6 address record.
|
||||
static constexpr uint16_t kTypeSrv = 33; ///< SRV locator record.
|
||||
static constexpr uint16_t kTypeOpt = 41; ///< Option record.
|
||||
static constexpr uint16_t kTypeNsec = 47; ///< NSEC record.
|
||||
static constexpr uint16_t kTypeAny = 255; ///< ANY record.
|
||||
|
||||
// Resource Record Class Codes.
|
||||
@@ -2745,6 +2746,104 @@ private:
|
||||
uint32_t mKeyLeaseInterval;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* Implements body format of NSEC record (RFC 3845) for use with mDNS.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class NsecRecord : public ResourceRecord
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t kType = kTypeNsec; ///< The NSEC record type.
|
||||
|
||||
/**
|
||||
* Represents NSEC Type Bit Map field (RFC 3845 - section 2.1.2)
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class TypeBitMap : public Clearable<TypeBitMap>
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kMinSize = 2; ///< Minimum size of a valid `TypeBitMap` (with zero length).
|
||||
|
||||
static constexpr uint8_t kMaxLength = 32; ///< Maximum BitmapLength value.
|
||||
|
||||
/**
|
||||
* Gets the Window Block Number
|
||||
*
|
||||
* @returns The Window Block Number.
|
||||
*
|
||||
*/
|
||||
uint8_t GetBlockNumber(void) const { return mBlockNumber; }
|
||||
|
||||
/**
|
||||
* Sets the Window Block Number
|
||||
*
|
||||
* @param[in] aBlockNumber The Window Block Number.
|
||||
*
|
||||
*/
|
||||
void SetBlockNumber(uint8_t aBlockNumber) { mBlockNumber = aBlockNumber; }
|
||||
|
||||
/**
|
||||
* Gets the Bitmap length
|
||||
*
|
||||
* @returns The Bitmap length
|
||||
*
|
||||
*/
|
||||
uint8_t GetBitmapLength(void) { return mBitmapLength; }
|
||||
|
||||
/**
|
||||
* Gets the total size (number of bytes) of the `TypeBitMap` field.
|
||||
*
|
||||
* @returns The size of the `TypeBitMap`
|
||||
*
|
||||
*/
|
||||
uint16_t GetSize(void) const { return (sizeof(mBlockNumber) + sizeof(mBitmapLength) + mBitmapLength); }
|
||||
|
||||
/**
|
||||
* Adds a resource record type to the Bitmap.
|
||||
*
|
||||
* As the types are added to the Bitmap the Bitmap length gets updated accordingly.
|
||||
*
|
||||
* The type space is split into 256 window blocks, each representing the low-order 8 bits of the 16-bit type
|
||||
* value. If @p aType does not match the currently set Window Block Number, no action is performed.
|
||||
*
|
||||
* @param[in] aType The resource record type to add.
|
||||
*
|
||||
*/
|
||||
void AddType(uint16_t aType);
|
||||
|
||||
/**
|
||||
* Indicates whether a given resource record type is present in the Bitmap.
|
||||
*
|
||||
* If @p aType does not match the currently set Window Block Number, this method returns `false`..
|
||||
*
|
||||
* @param[in] aType The resource record type to check.
|
||||
*
|
||||
* @retval TRUE The @p aType is present in the Bitmap.
|
||||
* @retval FALSE The @p aType is not present in the Bitmap.
|
||||
*
|
||||
*/
|
||||
bool ContainsType(uint16_t aType) const;
|
||||
|
||||
private:
|
||||
uint8_t mBlockNumber;
|
||||
uint8_t mBitmapLength;
|
||||
uint8_t mBitmaps[kMaxLength];
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* Initializes the NSEC Resource Record by setting its type and class.
|
||||
*
|
||||
* Other record fields (TTL, length remain unchanged/uninitialized.
|
||||
*
|
||||
* @param[in] aClass The class of the resource record (default is `kClassInternet`).
|
||||
*
|
||||
*/
|
||||
void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeNsec, aClass); }
|
||||
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* Implements Question format.
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -98,6 +98,7 @@
|
||||
#include "config/link_raw.h"
|
||||
#include "config/logging.h"
|
||||
#include "config/mac.h"
|
||||
#include "config/mdns.h"
|
||||
#include "config/mesh_diag.h"
|
||||
#include "config/mesh_forwarder.h"
|
||||
#include "config/misc.h"
|
||||
|
||||
@@ -135,6 +135,7 @@ add_library(openthread-posix
|
||||
infra_if.cpp
|
||||
logging.cpp
|
||||
mainloop.cpp
|
||||
mdns_socket.cpp
|
||||
memory.cpp
|
||||
misc.cpp
|
||||
multicast_routing.cpp
|
||||
|
||||
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*/
|
||||
|
||||
#include "mdns_socket.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ip6_utils.hpp"
|
||||
#include "platform-posix.h"
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
extern "C" otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
||||
{
|
||||
return ot::Posix::MdnsSocket::Get().SetListeningEnabled(aInstance, aEnable, aInfraIfIndex);
|
||||
}
|
||||
|
||||
extern "C" void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return ot::Posix::MdnsSocket::Get().SendMulticast(aMessage, aInfraIfIndex);
|
||||
}
|
||||
|
||||
extern "C" void otPlatMdnsSendUnicast(otInstance *aInstance, otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return ot::Posix::MdnsSocket::Get().SendUnicast(aMessage, aAddress);
|
||||
}
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
using namespace ot::Posix::Ip6Utils;
|
||||
|
||||
const char MdnsSocket::kLogModuleName[] = "MdnsSocket";
|
||||
|
||||
MdnsSocket &MdnsSocket::Get(void)
|
||||
{
|
||||
static MdnsSocket sInstance;
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
void MdnsSocket::Init(void)
|
||||
{
|
||||
mEnabled = false;
|
||||
mInfraIfIndex = 0;
|
||||
mFd6 = -1;
|
||||
mFd4 = -1;
|
||||
mPendingIp6Tx = 0;
|
||||
mPendingIp4Tx = 0;
|
||||
|
||||
// mDNS multicast IPv6 address "ff02::fb"
|
||||
memset(&mMulticastIp6Address, 0, sizeof(otIp6Address));
|
||||
mMulticastIp6Address.mFields.m8[0] = 0xff;
|
||||
mMulticastIp6Address.mFields.m8[1] = 0x02;
|
||||
mMulticastIp6Address.mFields.m8[15] = 0xfb;
|
||||
|
||||
// mDNS multicast IPv4 address "224.0.0.251"
|
||||
memset(&mMulticastIp4Address, 0, sizeof(otIp4Address));
|
||||
mMulticastIp4Address.mFields.m8[0] = 224;
|
||||
mMulticastIp4Address.mFields.m8[3] = 251;
|
||||
|
||||
memset(&mTxQueue, 0, sizeof(mTxQueue));
|
||||
}
|
||||
|
||||
void MdnsSocket::SetUp(void)
|
||||
{
|
||||
otMessageQueueInit(&mTxQueue);
|
||||
Mainloop::Manager::Get().Add(*this);
|
||||
}
|
||||
|
||||
void MdnsSocket::TearDown(void)
|
||||
{
|
||||
Mainloop::Manager::Get().Remove(*this);
|
||||
|
||||
if (mEnabled)
|
||||
{
|
||||
ClearTxQueue();
|
||||
mEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MdnsSocket::Deinit(void)
|
||||
{
|
||||
CloseIp4Socket();
|
||||
CloseIp6Socket();
|
||||
}
|
||||
|
||||
void MdnsSocket::Update(otSysMainloopContext &aContext)
|
||||
{
|
||||
VerifyOrExit(mEnabled);
|
||||
|
||||
FD_SET(mFd6, &aContext.mReadFdSet);
|
||||
FD_SET(mFd4, &aContext.mReadFdSet);
|
||||
|
||||
if (mPendingIp6Tx > 0)
|
||||
{
|
||||
FD_SET(mFd6, &aContext.mWriteFdSet);
|
||||
}
|
||||
|
||||
if (mPendingIp4Tx > 0)
|
||||
{
|
||||
FD_SET(mFd4, &aContext.mWriteFdSet);
|
||||
}
|
||||
|
||||
if (aContext.mMaxFd < mFd6)
|
||||
{
|
||||
aContext.mMaxFd = mFd6;
|
||||
}
|
||||
|
||||
if (aContext.mMaxFd < mFd4)
|
||||
{
|
||||
aContext.mMaxFd = mFd4;
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MdnsSocket::Process(const otSysMainloopContext &aContext)
|
||||
{
|
||||
VerifyOrExit(mEnabled);
|
||||
|
||||
if (FD_ISSET(mFd6, &aContext.mWriteFdSet))
|
||||
{
|
||||
SendQueuedMessages(kIp6Msg);
|
||||
}
|
||||
|
||||
if (FD_ISSET(mFd4, &aContext.mWriteFdSet))
|
||||
{
|
||||
SendQueuedMessages(kIp4Msg);
|
||||
}
|
||||
|
||||
if (FD_ISSET(mFd6, &aContext.mReadFdSet))
|
||||
{
|
||||
ReceiveMessage(kIp6Msg);
|
||||
}
|
||||
|
||||
if (FD_ISSET(mFd4, &aContext.mReadFdSet))
|
||||
{
|
||||
ReceiveMessage(kIp4Msg);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
otError MdnsSocket::SetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(aEnable != mEnabled);
|
||||
mInstance = aInstance;
|
||||
|
||||
if (aEnable)
|
||||
{
|
||||
error = Enable(aInfraIfIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Disable(aInfraIfIndex);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError MdnsSocket::Enable(uint32_t aInfraIfIndex)
|
||||
{
|
||||
otError error;
|
||||
|
||||
SuccessOrExit(error = OpenIp4Socket(aInfraIfIndex));
|
||||
SuccessOrExit(error = JoinOrLeaveIp4MulticastGroup(/* aJoin */ true, aInfraIfIndex));
|
||||
|
||||
SuccessOrExit(error = OpenIp6Socket(aInfraIfIndex));
|
||||
SuccessOrExit(error = JoinOrLeaveIp6MulticastGroup(/* aJoin */ true, aInfraIfIndex));
|
||||
|
||||
mEnabled = true;
|
||||
mInfraIfIndex = aInfraIfIndex;
|
||||
|
||||
LogInfo("Enabled");
|
||||
|
||||
exit:
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
CloseIp4Socket();
|
||||
CloseIp6Socket();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void MdnsSocket::Disable(uint32_t aInfraIfIndex)
|
||||
{
|
||||
ClearTxQueue();
|
||||
|
||||
IgnoreError(JoinOrLeaveIp4MulticastGroup(/* aJoin */ false, aInfraIfIndex));
|
||||
IgnoreError(JoinOrLeaveIp6MulticastGroup(/* aJoin */ false, aInfraIfIndex));
|
||||
CloseIp4Socket();
|
||||
CloseIp6Socket();
|
||||
|
||||
mEnabled = false;
|
||||
|
||||
LogInfo("Disabled");
|
||||
}
|
||||
|
||||
void MdnsSocket::SendMulticast(otMessage *aMessage, uint32_t aInfraIfIndex)
|
||||
{
|
||||
Metadata metadata;
|
||||
uint16_t length;
|
||||
|
||||
VerifyOrExit(mEnabled);
|
||||
VerifyOrExit(aInfraIfIndex == mInfraIfIndex);
|
||||
|
||||
length = otMessageGetLength(aMessage);
|
||||
|
||||
if (length > kMaxMessageLength)
|
||||
{
|
||||
LogWarn("Multicast msg length %u is longer than max %u", length, kMaxMessageLength);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
metadata.mIp6Address = mMulticastIp6Address;
|
||||
metadata.mIp6Port = kMdnsPort;
|
||||
metadata.mIp4Address = mMulticastIp4Address;
|
||||
metadata.mIp4Port = kMdnsPort;
|
||||
|
||||
SuccessOrExit(otMessageAppend(aMessage, &metadata, sizeof(Metadata)));
|
||||
|
||||
mPendingIp4Tx++;
|
||||
mPendingIp6Tx++;
|
||||
|
||||
otMessageQueueEnqueue(&mTxQueue, aMessage);
|
||||
aMessage = NULL;
|
||||
|
||||
exit:
|
||||
if (aMessage != NULL)
|
||||
{
|
||||
otMessageFree(aMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void MdnsSocket::SendUnicast(otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
|
||||
{
|
||||
bool isIp4 = false;
|
||||
Metadata metadata;
|
||||
uint16_t length;
|
||||
|
||||
VerifyOrExit(mEnabled);
|
||||
VerifyOrExit(aAddress->mInfraIfIndex == mInfraIfIndex);
|
||||
|
||||
length = otMessageGetLength(aMessage);
|
||||
|
||||
if (length > kMaxMessageLength)
|
||||
{
|
||||
LogWarn("Unicast msg length %u is longer than max %u", length, kMaxMessageLength);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
memset(&metadata, 0, sizeof(Metadata));
|
||||
|
||||
if (otIp4FromIp4MappedIp6Address(&aAddress->mAddress, &metadata.mIp4Address) == OT_ERROR_NONE)
|
||||
{
|
||||
isIp4 = true;
|
||||
metadata.mIp4Port = aAddress->mPort;
|
||||
metadata.mIp6Port = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
metadata.mIp6Address = aAddress->mAddress;
|
||||
metadata.mIp4Port = 0;
|
||||
metadata.mIp6Port = aAddress->mPort;
|
||||
}
|
||||
|
||||
SuccessOrExit(otMessageAppend(aMessage, &metadata, sizeof(Metadata)));
|
||||
|
||||
if (isIp4)
|
||||
{
|
||||
mPendingIp4Tx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPendingIp6Tx++;
|
||||
}
|
||||
|
||||
otMessageQueueEnqueue(&mTxQueue, aMessage);
|
||||
aMessage = NULL;
|
||||
|
||||
exit:
|
||||
if (aMessage != NULL)
|
||||
{
|
||||
otMessageFree(aMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void MdnsSocket::ClearTxQueue(void)
|
||||
{
|
||||
otMessage *message;
|
||||
|
||||
while ((message = otMessageQueueGetHead(&mTxQueue)) != NULL)
|
||||
{
|
||||
otMessageQueueDequeue(&mTxQueue, message);
|
||||
otMessageFree(message);
|
||||
}
|
||||
|
||||
mPendingIp4Tx = 0;
|
||||
mPendingIp6Tx = 0;
|
||||
}
|
||||
|
||||
void MdnsSocket::SendQueuedMessages(MsgType aMsgType)
|
||||
{
|
||||
switch (aMsgType)
|
||||
{
|
||||
case kIp6Msg:
|
||||
VerifyOrExit(mPendingIp6Tx > 0);
|
||||
break;
|
||||
case kIp4Msg:
|
||||
VerifyOrExit(mPendingIp4Tx > 0);
|
||||
break;
|
||||
}
|
||||
|
||||
for (otMessage *message = otMessageQueueGetHead(&mTxQueue); message != NULL;
|
||||
message = otMessageQueueGetNext(&mTxQueue, message))
|
||||
{
|
||||
bool isTxPending = false;
|
||||
uint16_t length;
|
||||
uint16_t offset;
|
||||
int bytesSent;
|
||||
Metadata metadata;
|
||||
uint8_t buffer[kMaxMessageLength];
|
||||
struct sockaddr_in6 addr6;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
length = otMessageGetLength(message);
|
||||
|
||||
offset = length - sizeof(Metadata);
|
||||
length -= sizeof(Metadata);
|
||||
|
||||
otMessageRead(message, offset, &metadata, sizeof(Metadata));
|
||||
|
||||
switch (aMsgType)
|
||||
{
|
||||
case kIp6Msg:
|
||||
isTxPending = (metadata.mIp6Port != 0);
|
||||
break;
|
||||
case kIp4Msg:
|
||||
isTxPending = (metadata.mIp4Port != 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isTxPending)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
otMessageRead(message, 0, buffer, length);
|
||||
|
||||
switch (aMsgType)
|
||||
{
|
||||
case kIp6Msg:
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(metadata.mIp6Port);
|
||||
CopyIp6AddressTo(metadata.mIp6Address, &addr6.sin6_addr);
|
||||
bytesSent = sendto(mFd6, buffer, length, 0, reinterpret_cast<struct sockaddr *>(&addr6), sizeof(addr6));
|
||||
VerifyOrExit(bytesSent == length);
|
||||
metadata.mIp6Port = 0;
|
||||
mPendingIp6Tx--;
|
||||
break;
|
||||
|
||||
case kIp4Msg:
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(metadata.mIp4Port);
|
||||
memcpy(&addr.sin_addr.s_addr, &metadata.mIp4Address, sizeof(otIp4Address));
|
||||
bytesSent = sendto(mFd4, buffer, length, 0, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
|
||||
VerifyOrExit(bytesSent == length);
|
||||
metadata.mIp4Port = 0;
|
||||
mPendingIp4Tx--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (metadata.CanFreeMessage())
|
||||
{
|
||||
otMessageQueueDequeue(&mTxQueue, message);
|
||||
otMessageFree(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
otMessageWrite(message, offset, &metadata, sizeof(Metadata));
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MdnsSocket::ReceiveMessage(MsgType aMsgType)
|
||||
{
|
||||
otMessage *message = nullptr;
|
||||
uint8_t buffer[kMaxMessageLength];
|
||||
otPlatMdnsAddressInfo addrInfo;
|
||||
uint16_t length = 0;
|
||||
struct sockaddr_in6 sockaddr6;
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t len = sizeof(sockaddr6);
|
||||
ssize_t rval;
|
||||
|
||||
memset(&addrInfo, 0, sizeof(addrInfo));
|
||||
|
||||
switch (aMsgType)
|
||||
{
|
||||
case kIp6Msg:
|
||||
len = sizeof(sockaddr6);
|
||||
memset(&sockaddr6, 0, sizeof(sockaddr6));
|
||||
rval = recvfrom(mFd6, reinterpret_cast<char *>(&buffer), sizeof(buffer), 0,
|
||||
reinterpret_cast<struct sockaddr *>(&sockaddr6), &len);
|
||||
VerifyOrExit(rval >= 0, LogCrit("recvfrom() for IPv6 socket failed, errno: %s", strerror(errno)));
|
||||
length = static_cast<uint16_t>(rval);
|
||||
ReadIp6AddressFrom(&sockaddr6.sin6_addr, addrInfo.mAddress);
|
||||
break;
|
||||
|
||||
case kIp4Msg:
|
||||
len = sizeof(sockaddr);
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
rval = recvfrom(mFd4, reinterpret_cast<char *>(&buffer), sizeof(buffer), 0,
|
||||
reinterpret_cast<struct sockaddr *>(&sockaddr), &len);
|
||||
VerifyOrExit(rval >= 0, LogCrit("recvfrom() for IPv4 socket failed, errno: %s", strerror(errno)));
|
||||
length = static_cast<uint16_t>(rval);
|
||||
otIp4ToIp4MappedIp6Address((otIp4Address *)(&sockaddr.sin_addr.s_addr), &addrInfo.mAddress);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyOrExit(length > 0);
|
||||
|
||||
message = otIp6NewMessage(mInstance, nullptr);
|
||||
VerifyOrExit(message != nullptr);
|
||||
SuccessOrExit(otMessageAppend(message, buffer, length));
|
||||
|
||||
addrInfo.mPort = kMdnsPort;
|
||||
addrInfo.mInfraIfIndex = mInfraIfIndex;
|
||||
|
||||
otPlatMdnsHandleReceive(mInstance, message, /* aInUnicast */ false, &addrInfo);
|
||||
message = nullptr;
|
||||
|
||||
exit:
|
||||
if (message != nullptr)
|
||||
{
|
||||
otMessageFree(message);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Socket helpers
|
||||
|
||||
otError MdnsSocket::OpenIp4Socket(uint32_t aInfraIfIndex)
|
||||
{
|
||||
otError error = OT_ERROR_FAILED;
|
||||
struct sockaddr_in addr;
|
||||
int fd;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
VerifyOrExit(fd >= 0, LogCrit("Failed to create IPv4 socket"));
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
char nameBuffer[IF_NAMESIZE];
|
||||
const char *ifname;
|
||||
|
||||
ifname = if_indextoname(aInfraIfIndex, nameBuffer);
|
||||
VerifyOrExit(ifname != NULL, LogCrit("if_indextoname() failed"));
|
||||
|
||||
error = SetSocketOptionValue(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname), "SO_BINDTODEVICE");
|
||||
SuccessOrExit(error);
|
||||
}
|
||||
#else
|
||||
{
|
||||
int ifindex = static_cast<int>(aInfraIfIndex);
|
||||
|
||||
SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IP, IP_BOUND_IF, ifindex, "IP_BOUND_IF"));
|
||||
}
|
||||
#endif
|
||||
|
||||
SuccessOrExit(error = SetSocketOption<uint8_t>(fd, IPPROTO_IP, IP_MULTICAST_TTL, 255, "IP_MULTICAST_TTL"));
|
||||
SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IP, IP_TTL, 255, "IP_TTL"));
|
||||
SuccessOrExit(error = SetSocketOption<uint8_t>(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 1, "IP_MULTICAST_LOOP"));
|
||||
SuccessOrExit(error = SetReuseAddrPortOptions(fd));
|
||||
|
||||
{
|
||||
struct ip_mreqn mreqn;
|
||||
|
||||
memset(&mreqn, 0, sizeof(mreqn));
|
||||
mreqn.imr_multiaddr.s_addr = inet_addr("224.0.0.251");
|
||||
mreqn.imr_ifindex = aInfraIfIndex;
|
||||
|
||||
SuccessOrExit(
|
||||
error = SetSocketOptionValue(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn), "IP_MULTICAST_IF"));
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(kMdnsPort);
|
||||
|
||||
if (bind(fd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) < 0)
|
||||
{
|
||||
LogCrit("bind() to mDNS port for IPv4 socket failed, errno: %s", strerror(errno));
|
||||
error = OT_ERROR_FAILED;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
mFd4 = fd;
|
||||
|
||||
LogInfo("Successfully opened IPv4 socket");
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError MdnsSocket::JoinOrLeaveIp4MulticastGroup(bool aJoin, uint32_t aInfraIfIndex)
|
||||
{
|
||||
struct ip_mreqn mreqn;
|
||||
|
||||
memset(&mreqn, 0, sizeof(mreqn));
|
||||
memcpy(&mreqn.imr_multiaddr.s_addr, &mMulticastIp4Address, sizeof(otIp4Address));
|
||||
mreqn.imr_ifindex = aInfraIfIndex;
|
||||
|
||||
if (aJoin)
|
||||
{
|
||||
// Suggested workaround for netif not dropping
|
||||
// a previous multicast membership.
|
||||
setsockopt(mFd4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
|
||||
}
|
||||
|
||||
return SetSocketOption(mFd4, IPPROTO_IP, aJoin ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, mreqn,
|
||||
"IP_ADD/DROP_MEMBERSHIP");
|
||||
}
|
||||
|
||||
void MdnsSocket::CloseIp4Socket(void)
|
||||
{
|
||||
if (mFd4 >= 0)
|
||||
{
|
||||
close(mFd4);
|
||||
mFd4 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
otError MdnsSocket::OpenIp6Socket(uint32_t aInfraIfIndex)
|
||||
{
|
||||
otError error = OT_ERROR_FAILED;
|
||||
struct sockaddr_in6 addr6;
|
||||
int fd;
|
||||
int ifindex = static_cast<int>(aInfraIfIndex);
|
||||
|
||||
fd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
VerifyOrExit(fd >= 0, LogCrit("Failed to create IPv4 socket"));
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
char nameBuffer[IF_NAMESIZE];
|
||||
const char *ifname;
|
||||
|
||||
ifname = if_indextoname(aInfraIfIndex, nameBuffer);
|
||||
VerifyOrExit(ifname != NULL, LogCrit("if_indextoname() failed"));
|
||||
|
||||
error = SetSocketOptionValue(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname), "SO_BINDTODEVICE");
|
||||
SuccessOrExit(error);
|
||||
}
|
||||
#else
|
||||
{
|
||||
SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_BOUND_IF, ifindex, "IPV6_BOUND_IF"));
|
||||
}
|
||||
#endif
|
||||
|
||||
SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255, "IPV6_MULTICAST_HOPS"));
|
||||
SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 255, "IPV6_UNICAST_HOPS"));
|
||||
SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_V6ONLY, 1, "IPV6_V6ONLY"));
|
||||
SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, ifindex, "IPV6_MULTICAST_IF"));
|
||||
SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 1, "IPV6_MULTICAST_LOOP"));
|
||||
SuccessOrExit(error = SetReuseAddrPortOptions(fd));
|
||||
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(kMdnsPort);
|
||||
|
||||
if (bind(fd, reinterpret_cast<struct sockaddr *>(&addr6), sizeof(addr6)) < 0)
|
||||
{
|
||||
LogCrit("bind() to mDNS port for IPv6 socket failed, errno: %s", strerror(errno));
|
||||
error = OT_ERROR_FAILED;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
mFd6 = fd;
|
||||
|
||||
LogInfo("Successfully opened IPv6 socket");
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifndef IPV6_ADD_MEMBERSHIP
|
||||
#ifdef IPV6_JOIN_GROUP
|
||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef IPV6_DROP_MEMBERSHIP
|
||||
#ifdef IPV6_LEAVE_GROUP
|
||||
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
otError MdnsSocket::JoinOrLeaveIp6MulticastGroup(bool aJoin, uint32_t aInfraIfIndex)
|
||||
{
|
||||
struct ipv6_mreq mreq6;
|
||||
|
||||
memset(&mreq6, 0, sizeof(mreq6));
|
||||
Ip6Utils::CopyIp6AddressTo(mMulticastIp6Address, &mreq6.ipv6mr_multiaddr);
|
||||
|
||||
mreq6.ipv6mr_interface = static_cast<int>(aInfraIfIndex);
|
||||
|
||||
if (aJoin)
|
||||
{
|
||||
// Suggested workaround for netif not dropping
|
||||
// a previous multicast membership.
|
||||
setsockopt(mFd6, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
|
||||
}
|
||||
|
||||
return SetSocketOptionValue(mFd6, IPPROTO_IPV6, aJoin ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6,
|
||||
sizeof(mreq6), "IP6_ADD/DROP_MEMBERSHIP");
|
||||
}
|
||||
|
||||
void MdnsSocket::CloseIp6Socket(void)
|
||||
{
|
||||
if (mFd6 >= 0)
|
||||
{
|
||||
close(mFd6);
|
||||
mFd6 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
otError MdnsSocket::SetReuseAddrPortOptions(int aFd)
|
||||
{
|
||||
otError error;
|
||||
|
||||
SuccessOrExit(error = SetSocketOption<int>(aFd, SOL_SOCKET, SO_REUSEADDR, 1, "SO_REUSEADDR"));
|
||||
SuccessOrExit(error = SetSocketOption<int>(aFd, SOL_SOCKET, SO_REUSEPORT, 1, "SO_REUSEPORT"));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError MdnsSocket::SetSocketOptionValue(int aFd,
|
||||
int aLevel,
|
||||
int aOption,
|
||||
const void *aValue,
|
||||
uint32_t aValueLength,
|
||||
const char *aOptionName)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
if (setsockopt(aFd, aLevel, aOption, aValue, aValueLength) != 0)
|
||||
{
|
||||
error = OT_ERROR_FAILED;
|
||||
LogCrit("Failed to setsockopt(%s) - errno: %s", aOptionName, strerror(errno));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*/
|
||||
#ifndef OT_POSIX_PLATFORM_MDNS_SOCKET_HPP_
|
||||
#define OT_POSIX_PLATFORM_MDNS_SOCKET_HPP_
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
|
||||
#include <openthread/nat64.h>
|
||||
#include <openthread/platform/mdns_socket.h>
|
||||
|
||||
#include "logger.hpp"
|
||||
#include "mainloop.hpp"
|
||||
|
||||
#include "core/common/non_copyable.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
/**
|
||||
* Implements platform mDNS socket APIs.
|
||||
*
|
||||
*/
|
||||
class MdnsSocket : public Mainloop::Source, public Logger<MdnsSocket>, private NonCopyable
|
||||
{
|
||||
public:
|
||||
static const char kLogModuleName[]; ///< Module name used for logging.
|
||||
|
||||
/**
|
||||
* Gets the `MdnsSocket` singleton.
|
||||
*
|
||||
* @returns The singleton object.
|
||||
*
|
||||
*/
|
||||
static MdnsSocket &Get(void);
|
||||
|
||||
/**
|
||||
* Initializes the `MdnsSocket`.
|
||||
*
|
||||
* Called before OpenThread instance is created.
|
||||
*
|
||||
*/
|
||||
void Init(void);
|
||||
|
||||
/**
|
||||
* Sets up the `MdnsSocket`.
|
||||
*
|
||||
* Called after OpenThread instance is created.
|
||||
*
|
||||
*/
|
||||
void SetUp(void);
|
||||
|
||||
/**
|
||||
* Tears down the `MdnsSocket`.
|
||||
*
|
||||
* Called before OpenThread instance is destructed.
|
||||
*
|
||||
*/
|
||||
void TearDown(void);
|
||||
|
||||
/**
|
||||
* Deinitializes the `MdnsSocket`.
|
||||
*
|
||||
* Called after OpenThread instance is destructed.
|
||||
*
|
||||
*/
|
||||
void Deinit(void);
|
||||
|
||||
/**
|
||||
* Updates the fd_set and timeout for mainloop.
|
||||
*
|
||||
* @param[in,out] aContext A reference to the mainloop context.
|
||||
*
|
||||
*/
|
||||
void Update(otSysMainloopContext &aContext) override;
|
||||
|
||||
/**
|
||||
* Performs `MdnsSocket` processing.
|
||||
*
|
||||
* @param[in] aContext A reference to the mainloop context.
|
||||
*
|
||||
*/
|
||||
void Process(const otSysMainloopContext &aContext) override;
|
||||
|
||||
// otPlatMdns APIs
|
||||
otError SetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex);
|
||||
void SendMulticast(otMessage *aMessage, uint32_t aInfraIfIndex);
|
||||
void SendUnicast(otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kMaxMessageLength = 2000;
|
||||
static constexpr uint16_t kMdnsPort = 5353;
|
||||
|
||||
enum MsgType : uint8_t
|
||||
{
|
||||
kIp6Msg,
|
||||
kIp4Msg,
|
||||
};
|
||||
|
||||
struct Metadata
|
||||
{
|
||||
bool CanFreeMessage(void) const { return (mIp6Port == 0) && (mIp4Port == 0); }
|
||||
|
||||
otIp6Address mIp6Address;
|
||||
uint16_t mIp6Port;
|
||||
otIp4Address mIp4Address;
|
||||
uint16_t mIp4Port;
|
||||
};
|
||||
|
||||
bool mEnabled;
|
||||
uint32_t mInfraIfIndex;
|
||||
int mFd4;
|
||||
int mFd6;
|
||||
uint32_t mPendingIp6Tx;
|
||||
uint32_t mPendingIp4Tx;
|
||||
otMessageQueue mTxQueue;
|
||||
otIp6Address mMulticastIp6Address;
|
||||
otIp4Address mMulticastIp4Address;
|
||||
otInstance *mInstance;
|
||||
|
||||
otError Enable(uint32_t aInfraIfIndex);
|
||||
void Disable(uint32_t aInfraIfIndex);
|
||||
void ClearTxQueue(void);
|
||||
void SendQueuedMessages(MsgType aMsgType);
|
||||
void ReceiveMessage(MsgType aMsgType);
|
||||
|
||||
otError OpenIp4Socket(uint32_t aInfraIfIndex);
|
||||
otError JoinOrLeaveIp4MulticastGroup(bool aJoin, uint32_t aInfraIfIndex);
|
||||
void CloseIp4Socket(void);
|
||||
otError OpenIp6Socket(uint32_t aInfraIfIndex);
|
||||
otError JoinOrLeaveIp6MulticastGroup(bool aJoin, uint32_t aInfraIfIndex);
|
||||
void CloseIp6Socket(void);
|
||||
|
||||
static otError SetReuseAddrPortOptions(int aFd);
|
||||
|
||||
template <typename ValueType>
|
||||
static otError SetSocketOption(int aFd, int aLevel, int aOption, const ValueType &aValue, const char *aOptionName)
|
||||
{
|
||||
return SetSocketOptionValue(aFd, aLevel, aOption, &aValue, sizeof(ValueType), aOptionName);
|
||||
}
|
||||
|
||||
static otError SetSocketOptionValue(int aFd,
|
||||
int aLevel,
|
||||
int aOption,
|
||||
const void *aValue,
|
||||
uint32_t aValueLength,
|
||||
const char *aOptionName);
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
|
||||
#endif // OT_POSIX_PLATFORM_MDNS_SOCKET_HPP_
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "posix/platform/firewall.hpp"
|
||||
#include "posix/platform/infra_if.hpp"
|
||||
#include "posix/platform/mainloop.hpp"
|
||||
#include "posix/platform/mdns_socket.hpp"
|
||||
#include "posix/platform/radio_url.hpp"
|
||||
#include "posix/platform/udp.hpp"
|
||||
|
||||
@@ -145,7 +146,10 @@ void platformInit(otPlatformConfig *aPlatformConfig)
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE
|
||||
ot::Posix::InfraNetif::Get().Init();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
ot::Posix::MdnsSocket::Get().Init();
|
||||
#endif
|
||||
|
||||
gNetifName[0] = '\0';
|
||||
@@ -197,6 +201,10 @@ void platformSetUp(otPlatformConfig *aPlatformConfig)
|
||||
ot::Posix::Udp::Get().SetUp();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
ot::Posix::MdnsSocket::Get().SetUp();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
|
||||
ot::Posix::Daemon::Get().SetUp();
|
||||
#endif
|
||||
@@ -244,6 +252,10 @@ void platformTearDown(void)
|
||||
ot::Posix::InfraNetif::Get().TearDown();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
ot::Posix::MdnsSocket::Get().TearDown();
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
@@ -272,6 +284,10 @@ void platformDeinit(void)
|
||||
ot::Posix::InfraNetif::Get().Deinit();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
ot::Posix::MdnsSocket::Get().Deinit();
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,12 +39,14 @@
|
||||
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_INFO "POSIX-toranj"
|
||||
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE 1
|
||||
|
||||
#ifdef __linux__
|
||||
#define OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE 1
|
||||
#endif
|
||||
|
||||
#ifndef OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE 0
|
||||
#endif
|
||||
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE 1
|
||||
|
||||
@@ -42,13 +42,14 @@
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_INFO "SIMULATION-RCP-toranj"
|
||||
#else
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_INFO "SIMULATION-toranj"
|
||||
|
||||
#endif
|
||||
|
||||
#define OPENTHREAD_CONFIG_COAP_API_ENABLE 1
|
||||
|
||||
#define OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE 1
|
||||
|
||||
#define OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX 1
|
||||
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 0
|
||||
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1
|
||||
|
||||
@@ -178,6 +178,10 @@
|
||||
|
||||
#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 1
|
||||
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE 1
|
||||
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE 1
|
||||
|
||||
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE 1
|
||||
|
||||
#define OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK 1
|
||||
|
||||
@@ -723,6 +723,27 @@ target_link_libraries(ot-test-macros
|
||||
|
||||
add_test(NAME ot-test-macros COMMAND ot-test-macros)
|
||||
|
||||
add_executable(ot-test-mdns
|
||||
test_mdns.cpp
|
||||
)
|
||||
|
||||
target_include_directories(ot-test-mdns
|
||||
PRIVATE
|
||||
${COMMON_INCLUDES}
|
||||
)
|
||||
|
||||
target_compile_options(ot-test-mdns
|
||||
PRIVATE
|
||||
${COMMON_COMPILE_OPTIONS}
|
||||
)
|
||||
|
||||
target_link_libraries(ot-test-mdns
|
||||
PRIVATE
|
||||
${COMMON_LIBS}
|
||||
)
|
||||
|
||||
add_test(NAME ot-test-mdns COMMAND ot-test-mdns)
|
||||
|
||||
add_executable(ot-test-message
|
||||
test_message.cpp
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -555,6 +555,35 @@ otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aTh
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
|
||||
OT_TOOL_WEAK otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aEnable);
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aMessage);
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatMdnsSendUnicast(otInstance *aInstance,
|
||||
otMessage *aMessage,
|
||||
const otPlatMdnsAddressInfo *aAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aMessage);
|
||||
OT_UNUSED_VARIABLE(aAddress);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
|
||||
OT_TOOL_WEAK void otPlatDsoEnableListening(otInstance *aInstance, bool aEnable)
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <openthread/platform/dso_transport.h>
|
||||
#include <openthread/platform/entropy.h>
|
||||
#include <openthread/platform/logging.h>
|
||||
#include <openthread/platform/mdns_socket.h>
|
||||
#include <openthread/platform/misc.h>
|
||||
#include <openthread/platform/multipan.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
Reference in New Issue
Block a user