From ec93c24007ca35bddfefd151ea46e0fe6983ddf6 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 11 Jul 2023 13:21:34 -0700 Subject: [PATCH] [srp-server] simplify sub-type services (#9208) This commit updates and simplifies how `Srp::Server` stores the sub-type services. The earlier implementation treated each sub-type as its own service, which was tracked by a `Service` object. This design allowed sub-type services to be registered and deleted individually. However, the latest SRP RFC draft requires SRP servers to treat updates to a service and all its sub-types as atomic. This means that when a service and its sub-types are being updated, the SRP Update message must contain the entirety of information about that service and its sub-types. As a result of this change, we can simplify the server implementation by tracking sub-types as an array of sub-type names in the `Service` object. This commit also updates the way the server commits a received SRP update info into its existing data. Previously, the server would try to merge the new information into existing `Host` and `Service` objects. However, this could be inefficient, as it would require moving heap-allocated items like "txt data" and/or array of host IPv6 addresses from one object to another. The new `CommitSrpUpdate()` implementation now starts from the new `Host` object that is constructed as the received SRP Update message from the client is parsed. Any previously registered services that are not present in the new `Host` object are then moved into it. This commit adds new public OT APIs for retrieving the sub-types associated with a service and making it easier to iterate over the list of registered services by a host. Due to fundamental changes in how services are stored by the `Srp::Server` class, some existing public `otSrpServer` APIs for filtering and iterating over services are being removed. --- include/openthread/instance.h | 2 +- include/openthread/srp_server.h | 243 +++++------ src/cli/cli_srp_server.cpp | 34 +- src/core/api/srp_server_api.cpp | 53 ++- src/core/net/dnssd_server.cpp | 80 ++-- src/core/net/dnssd_server.hpp | 21 +- src/core/net/srp_server.cpp | 710 ++++++++++++-------------------- src/core/net/srp_server.hpp | 264 +++++------- 8 files changed, 566 insertions(+), 841 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index a92a6b532..90366cd19 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (342) +#define OPENTHREAD_API_VERSION (343) /** * @addtogroup api-instance diff --git a/include/openthread/srp_server.h b/include/openthread/srp_server.h index 4a37b4614..8f45b0842 100644 --- a/include/openthread/srp_server.h +++ b/include/openthread/srp_server.h @@ -73,64 +73,6 @@ typedef struct otSrpServerService otSrpServerService; */ typedef uint32_t otSrpServerServiceUpdateId; -/** - * The service flag type to indicate which services to include or exclude when searching in (or iterating over) the - * list of SRP services. - * - * This is a combination of bit-flags. The specific bit-flags are defined in the enumeration `OT_SRP_SERVER_FLAG_*`. - * - */ -typedef uint8_t otSrpServerServiceFlags; - -enum -{ - OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE = 1 << 0, ///< Include base services (not a sub-type). - OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE = 1 << 1, ///< Include sub-type services. - OT_SRP_SERVER_SERVICE_FLAG_ACTIVE = 1 << 2, ///< Include active (not deleted) services. - OT_SRP_SERVER_SERVICE_FLAG_DELETED = 1 << 3, ///< Include deleted services. -}; - -enum -{ - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting any service (base/sub-type, - * active/deleted). - * - */ - OT_SRP_SERVER_FLAGS_ANY_SERVICE = (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | - OT_SRP_SERVER_SERVICE_FLAG_ACTIVE | OT_SRP_SERVER_SERVICE_FLAG_DELETED), - - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting base service only. - * - */ - OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY = - (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE | OT_SRP_SERVER_SERVICE_FLAG_DELETED), - - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting sub-type service only. - * - */ - OT_SRP_SERVER_FLAGS_SUB_TYPE_SERVICE_ONLY = - (OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE | OT_SRP_SERVER_SERVICE_FLAG_DELETED), - - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting any active service (not deleted). - * - */ - OT_SRP_SERVER_FLAGS_ANY_TYPE_ACTIVE_SERVICE = - (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | - OT_SRP_SERVER_SERVICE_FLAG_ACTIVE), - - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting any deleted service. - * - */ - OT_SRP_SERVER_FLAGS_ANY_TYPE_DELETED_SERVICE = - (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | - OT_SRP_SERVER_SERVICE_FLAG_ACTIVE), -}; - /** * Represents the state of the SRP server. * @@ -505,6 +447,21 @@ bool otSrpServerHostIsDeleted(const otSrpServerHost *aHost); */ const char *otSrpServerHostGetFullName(const otSrpServerHost *aHost); +/** + * Indicates whether the host matches a given host name. + * + * DNS name matches are performed using a case-insensitive string comparison (i.e., "Abc" and "aBc" are considered to + * be the same). + * + * @param[in] aHost A pointer to the SRP service host. + * @param[in] aFullName A full host name. + * + * @retval TRUE If host matches the host name. + * @retval FALSE If host does not match the host name. + * + */ +bool otSrpServerHostMatchesFullName(const otSrpServerHost *aHost, const char *aFullName); + /** * Returns the addresses of given host. * @@ -526,10 +483,7 @@ const otIp6Address *otSrpServerHostGetAddresses(const otSrpServerHost *aHost, ui void otSrpServerHostGetLeaseInfo(const otSrpServerHost *aHost, otSrpServerLeaseInfo *aLeaseInfo); /** - * Returns the next service (excluding any sub-type services) of given host. - * - * @note This function is being deprecated and will be removed. `otSrpServerHostFindNextService()` can be used - * instead. + * Returns the next service of given host. * * @param[in] aHost A pointer to the SRP service host. * @param[in] aService A pointer to current SRP service instance; use NULL to get the first service. @@ -540,44 +494,6 @@ void otSrpServerHostGetLeaseInfo(const otSrpServerHost *aHost, otSrpServerLeaseI const otSrpServerService *otSrpServerHostGetNextService(const otSrpServerHost *aHost, const otSrpServerService *aService); -/** - * Finds the next matching service on the host. - * - * The combination of flags and service and instance names enables iterating over the full list of services and/or a - * subset of them matching certain conditions, or finding a specific service. - * - * To iterate over all services of a host: - * service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_ANY_SERVICE, NULL, NULL); - * - * To iterate over base services only (exclude sub-types): - * service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY, NULL, NULL); - * - * To iterate over sub-types of a specific instance name `instanceName`: - * service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_SUB_TYPE_SERVICE_ONLY, NULL, - * instanceName); - * - * To find a specific service with service name `serviceName` and service instance name `instanceName`: - * service = otSrpServerHostFindNextService(host, NULL, OT_SRP_SERVER_FLAGS_ANY_SERVICE, serviceName, instanceName); - * - * To find the base type service with a given service instance name `instanceName`: - * service = otSrpServerHostFindNextService(host, NULL, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY, NULL, - * instanceName); - * - * @param[in] aHost A pointer to the SRP service host (MUST NOT be NULL). - * @param[in] aPrevService A pointer to the previous service or NULL to start from the beginning of the list. - * @param[in] aFlags Flags indicating which services to include (base/sub-type, active/deleted). - * @param[in] aServiceName The service name to match. Set to NULL to accept any name. - * @param[in] aInstanceName The service instance name to match. Set to NULL to accept any name. - * - * @returns A pointer to the next matching service or NULL if no matching service could be found. - * - */ -const otSrpServerService *otSrpServerHostFindNextService(const otSrpServerHost *aHost, - const otSrpServerService *aPrevService, - otSrpServerServiceFlags aFlags, - const char *aServiceName, - const char *aInstanceName); - /** * Indicates whether or not the SRP service has been deleted. * @@ -592,29 +508,6 @@ const otSrpServerService *otSrpServerHostFindNextService(const otSrpServerHost */ bool otSrpServerServiceIsDeleted(const otSrpServerService *aService); -/** - * Indicates whether or not the SRP service is sub-type. - * - * @param[in] aService A pointer to the SRP service. - * - * @returns TRUE if the service is a sub-type, FALSE if not. - * - */ -bool otSrpServerServiceIsSubType(const otSrpServerService *aService); - -/** - * Returns the full service instance name of the service. - * - * @note This function is being deprecated and will be removed. `otSrpServerServiceGetInstanceName()` can be used - * instead. - * - * @param[in] aService A pointer to the SRP service. - * - * @returns A pointer to the null-terminated service instance name string. - * - */ -const char *otSrpServerServiceGetFullName(const otSrpServerService *aService); - /** * Returns the full service instance name of the service. * @@ -625,6 +518,31 @@ const char *otSrpServerServiceGetFullName(const otSrpServerService *aService); */ const char *otSrpServerServiceGetInstanceName(const otSrpServerService *aService); +/** + * Indicates whether this service matches a given service instance name. + * + * DNS name matches are performed using a case-insensitive string comparison (i.e., "Abc" and "aBc" are considered to + * be the same). + * + * @param[in] aService A pointer to the SRP service. + * @param[in] aInstanceName The service instance name. + * + * @retval TRUE If service matches the service instance name. + * @retval FALSE If service does not match the service instance name. + * + */ +bool otSrpServerServiceMatchesInstanceName(const otSrpServerService *aService, const char *aInstanceName); + +/** + * Returns the service instance label (first label in instance name) of the service. + * + * @param[in] aService A pointer to the SRP service. + * + * @returns A pointer to the null-terminated service instance label string.. + * + */ +const char *otSrpServerServiceGetInstanceLabel(const otSrpServerService *aService); + /** * Returns the full service name of the service. * @@ -636,27 +554,74 @@ const char *otSrpServerServiceGetInstanceName(const otSrpServerService *aService const char *otSrpServerServiceGetServiceName(const otSrpServerService *aService); /** - * Gets the sub-type label from service name. + * Indicates whether this service matches a given service name. * - * Is intended to be used when the @p aService is a sub-type, i.e., `otSrpServerServiceIsSubType()` for - * the service returns TRUE. If it is not a sub-type this function returns `OT_ERROR_INVALID_ARGS`. + * DNS name matches are performed using a case-insensitive string comparison (i.e., "Abc" and "aBc" are considered to + * be the same). * - * The full service name for a sub-type service follows "._sub...". This function - * copies the `` into the @p aLabel buffer. + * @param[in] aService A pointer to the SRP service. + * @param[in] aServiceName The service name. * - * The @p aLabel is ensured to always be null-terminated after returning even in case of failure. - * - * @param[in] aService A pointer to the SRP service. - * @param[out] aLabel A pointer to a buffer to copy the sub-type label name into. - * @param[in] aMaxSize Maximum size of @p aLabel buffer. - * - * @retval OT_ERROR_NONE @p aLabel was updated successfully. - * @retval OT_ERROR_NO_BUFS The sub-type label could not fit in @p aLabel buffer (number of chars from label - * that could fit are copied in @p aLabel ensuring it is null-terminated). - * @retval OT_ERROR_INVALID_ARGS SRP service is not a sub-type. + * @retval TRUE If service matches the service name. + * @retval FALSE If service does not match the service name. * */ -otError otSrpServerServiceGetServiceSubTypeLabel(const otSrpServerService *aService, char *aLabel, uint8_t aMaxSize); +bool otSrpServerServiceMatchesServiceName(const otSrpServerService *aService, const char *aServiceName); + +/** + * Gets the number of sub-types of the service. + * + * @param[in] aService A pointer to the SRP service. + * + * @returns The number of sub-types of @p aService. + * + */ +uint16_t otSrpServerServiceGetNumberOfSubTypes(const otSrpServerService *aService); + +/** + * Gets the sub-type service name (full name) of the service at a given index + * + * The full service name for a sub-type service follows "._sub...". + * + * @param[in] aService A pointer to the SRP service. + * @param[in] aIndex The index to get. + * + * @returns A pointer to sub-type service name at @p aIndex, or `NULL` if no sub-type at this index. + * + */ +const char *otSrpServerServiceGetSubTypeServiceNameAt(const otSrpServerService *aService, uint16_t aIndex); + +/** + * Indicates whether or not the service has a given sub-type. + * + * DNS name matches are performed using a case-insensitive string comparison (i.e., "Abc" and "aBc" are considered to + * be the same). + * + * @param[in] aService A pointer to the SRP service. + * @param[in] aSubTypeServiceName The sub-type service name (full name) to check. + * + * @retval TRUE Service contains the sub-type @p aSubTypeServiceName. + * @retval FALSE Service does not contain the sub-type @p aSubTypeServiceName. + * + */ +bool otSrpServerServiceHasSubTypeServiceName(const otSrpServerService *aService, const char *aSubTypeServiceName); + +/** + * Parses a sub-type service name (full name) and extracts the sub-type label. + * + * The full service name for a sub-type service follows "._sub...". + * + * @param[in] aSubTypeServiceName A sub-type service name (full name). + * @param[out] aLabel A pointer to a buffer to copy the extracted sub-type label. + * @param[in] aLabelSize Maximum size of @p aLabel buffer. + * + * @retval OT_ERROR_NONE Name was successfully parsed and @p aLabel was updated. + * @retval OT_ERROR_NO_BUFS The sub-type label could not fit in @p aLabel buffer (number of chars from label + * that could fit are copied in @p aLabel ensuring it is null-terminated). + * @retval OT_ERROR_INVALID_ARGS @p aSubTypeServiceName is not a valid sub-type format. + * + */ +otError otSrpServerParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize); /** * Returns the port of the service instance. diff --git a/src/cli/cli_srp_server.cpp b/src/cli/cli_srp_server.cpp index 50281ade1..5a96d5fe6 100644 --- a/src/cli/cli_srp_server.cpp +++ b/src/cli/cli_srp_server.cpp @@ -270,9 +270,6 @@ void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost) template <> otError SrpServer::Process(Arg aArgs[]) { - static constexpr char *kAnyServiceName = nullptr; - static constexpr char *kAnyInstanceName = nullptr; - otError error = OT_ERROR_NONE; const otSrpServerHost *host = nullptr; @@ -282,18 +279,15 @@ template <> otError SrpServer::Process(Arg aArgs[]) { const otSrpServerService *service = nullptr; - while ((service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY, - kAnyServiceName, kAnyInstanceName)) != nullptr) + while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) { - bool isDeleted = otSrpServerServiceIsDeleted(service); - const char *instanceName = otSrpServerServiceGetInstanceName(service); - const otSrpServerService *subService = nullptr; - const uint8_t *txtData; - uint16_t txtDataLength; - bool hasSubType = false; - otSrpServerLeaseInfo leaseInfo; + bool isDeleted = otSrpServerServiceIsDeleted(service); + const uint8_t *txtData; + uint16_t txtDataLength; + bool hasSubType = false; + otSrpServerLeaseInfo leaseInfo; - OutputLine("%s", instanceName); + OutputLine("%s", otSrpServerServiceGetInstanceName(service)); OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false"); if (isDeleted) @@ -305,13 +299,17 @@ template <> otError SrpServer::Process(Arg aArgs[]) OutputFormat(kIndentSize, "subtypes: "); - while ((subService = otSrpServerHostFindNextService( - host, subService, (OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE), - kAnyServiceName, instanceName)) != nullptr) + for (uint16_t index = 0;; index++) { - char subLabel[OT_DNS_MAX_LABEL_SIZE]; + char subLabel[OT_DNS_MAX_LABEL_SIZE]; + const char *subTypeName = otSrpServerServiceGetSubTypeServiceNameAt(service, index); - IgnoreError(otSrpServerServiceGetServiceSubTypeLabel(subService, subLabel, sizeof(subLabel))); + if (subTypeName == nullptr) + { + break; + } + + IgnoreError(otSrpServerParseSubTypeServiceName(subTypeName, subLabel, sizeof(subLabel))); OutputFormat("%s%s", hasSubType ? "," : "", subLabel); hasSubType = true; } diff --git a/src/core/api/srp_server_api.cpp b/src/core/api/srp_server_api.cpp index a6a3ca7ca..4a0044b80 100644 --- a/src/core/api/srp_server_api.cpp +++ b/src/core/api/srp_server_api.cpp @@ -139,6 +139,11 @@ bool otSrpServerHostIsDeleted(const otSrpServerHost *aHost) { return AsCoreType( const char *otSrpServerHostGetFullName(const otSrpServerHost *aHost) { return AsCoreType(aHost).GetFullName(); } +bool otSrpServerHostMatchesFullName(const otSrpServerHost *aHost, const char *aFullName) +{ + return AsCoreType(aHost).Matches(aFullName); +} + const otIp6Address *otSrpServerHostGetAddresses(const otSrpServerHost *aHost, uint8_t *aAddressesNum) { return AsCoreType(aHost).GetAddresses(*aAddressesNum); @@ -154,30 +159,24 @@ uint32_t otSrpServerHostGetKeyLease(const otSrpServerHost *aHost) { return AsCor const otSrpServerService *otSrpServerHostGetNextService(const otSrpServerHost *aHost, const otSrpServerService *aService) { - return AsCoreType(aHost).FindNextService(AsCoreTypePtr(aService), Srp::Server::kFlagsBaseTypeServiceOnly); -} - -const otSrpServerService *otSrpServerHostFindNextService(const otSrpServerHost *aHost, - const otSrpServerService *aPrevService, - otSrpServerServiceFlags aFlags, - const char *aServiceName, - const char *aInstanceName) -{ - return AsCoreType(aHost).FindNextService(AsCoreTypePtr(aPrevService), aFlags, aServiceName, aInstanceName); + return AsCoreType(aHost).GetNextService(AsCoreTypePtr(aService)); } bool otSrpServerServiceIsDeleted(const otSrpServerService *aService) { return AsCoreType(aService).IsDeleted(); } -bool otSrpServerServiceIsSubType(const otSrpServerService *aService) { return AsCoreType(aService).IsSubType(); } - -const char *otSrpServerServiceGetFullName(const otSrpServerService *aService) +const char *otSrpServerServiceGetInstanceName(const otSrpServerService *aService) { return AsCoreType(aService).GetInstanceName(); } -const char *otSrpServerServiceGetInstanceName(const otSrpServerService *aService) +bool otSrpServerServiceMatchesInstanceName(const otSrpServerService *aService, const char *aInstanceName) { - return AsCoreType(aService).GetInstanceName(); + return AsCoreType(aService).MatchesInstanceName(aInstanceName); +} + +const char *otSrpServerServiceGetInstanceLabel(const otSrpServerService *aService) +{ + return AsCoreType(aService).GetInstanceLabel(); } const char *otSrpServerServiceGetServiceName(const otSrpServerService *aService) @@ -185,9 +184,29 @@ const char *otSrpServerServiceGetServiceName(const otSrpServerService *aService) return AsCoreType(aService).GetServiceName(); } -otError otSrpServerServiceGetServiceSubTypeLabel(const otSrpServerService *aService, char *aLabel, uint8_t aMaxSize) +bool otSrpServerServiceMatchesServiceName(const otSrpServerService *aService, const char *aServiceName) { - return AsCoreType(aService).GetServiceSubTypeLabel(aLabel, aMaxSize); + return AsCoreType(aService).MatchesServiceName(aServiceName); +} + +uint16_t otSrpServerServiceGetNumberOfSubTypes(const otSrpServerService *aService) +{ + return AsCoreType(aService).GetNumberOfSubTypes(); +} + +const char *otSrpServerServiceGetSubTypeServiceNameAt(const otSrpServerService *aService, uint16_t aIndex) +{ + return AsCoreType(aService).GetSubTypeServiceNameAt(aIndex); +} + +bool otSrpServerServiceHasSubTypeServiceName(const otSrpServerService *aService, const char *aSubTypeServiceName) +{ + return AsCoreType(aService).HasSubTypeServiceName(aSubTypeServiceName); +} + +otError otSrpServerParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize) +{ + return Srp::Server::Service::ParseSubTypeServiceName(aSubTypeServiceName, aLabel, aLabelSize); } uint16_t otSrpServerServiceGetPort(const otSrpServerService *aService) { return AsCoreType(aService).GetPort(); } diff --git a/src/core/net/dnssd_server.cpp b/src/core/net/dnssd_server.cpp index 478e4d8bf..19f5c8645 100644 --- a/src/core/net/dnssd_server.cpp +++ b/src/core/net/dnssd_server.cpp @@ -754,31 +754,46 @@ Header::Response Server::ResolveQuestionBySrp(const char *aName, NameCompressInfo &aCompressInfo, bool aAdditional) { - Error error = kErrorNone; - const Srp::Server::Host *host = nullptr; - TimeMilli now = TimerMilli::GetNow(); - uint16_t qtype = aQuestion.GetType(); - Header::Response response = Header::kResponseNameError; + Error error = kErrorNone; + TimeMilli now = TimerMilli::GetNow(); + uint16_t qtype = aQuestion.GetType(); + Header::Response response = Header::kResponseNameError; - while ((host = GetNextSrpHost(host)) != nullptr) + for (const Srp::Server::Host &host : Get().GetHosts()) { bool needAdditionalAaaaRecord = false; - const char *hostName = host->GetFullName(); + const char *hostName = host.GetFullName(); + + if (host.IsDeleted()) + { + continue; + } // Handle PTR/SRV/TXT query if (qtype == ResourceRecord::kTypePtr || qtype == ResourceRecord::kTypeSrv || qtype == ResourceRecord::kTypeTxt) { - const Srp::Server::Service *service = nullptr; - - while ((service = GetNextSrpService(*host, service)) != nullptr) + for (const Srp::Server::Service &service : host.GetServices()) { - uint32_t instanceTtl = TimeMilli::MsecToSec(service->GetExpireTime() - TimerMilli::GetNow()); - const char *instanceName = service->GetInstanceName(); - bool serviceNameMatched = service->MatchesServiceName(aName); - bool instanceNameMatched = service->MatchesInstanceName(aName); - bool ptrQueryMatched = qtype == ResourceRecord::kTypePtr && serviceNameMatched; - bool srvQueryMatched = qtype == ResourceRecord::kTypeSrv && instanceNameMatched; - bool txtQueryMatched = qtype == ResourceRecord::kTypeTxt && instanceNameMatched; + uint32_t instanceTtl; + const char *instanceName; + bool serviceNameMatched; + bool instanceNameMatched; + bool ptrQueryMatched; + bool srvQueryMatched; + bool txtQueryMatched; + + if (service.IsDeleted()) + { + continue; + } + + instanceTtl = TimeMilli::MsecToSec(service.GetExpireTime() - TimerMilli::GetNow()); + instanceName = service.GetInstanceName(); + serviceNameMatched = service.MatchesServiceName(aName) || service.HasSubTypeServiceName(aName); + instanceNameMatched = service.MatchesInstanceName(aName); + ptrQueryMatched = qtype == ResourceRecord::kTypePtr && serviceNameMatched; + srvQueryMatched = qtype == ResourceRecord::kTypeSrv && instanceNameMatched; + txtQueryMatched = qtype == ResourceRecord::kTypeTxt && instanceNameMatched; if (ptrQueryMatched || srvQueryMatched) { @@ -798,8 +813,8 @@ Header::Response Server::ResolveQuestionBySrp(const char *aName, !HasQuestion(aResponseHeader, aResponseMessage, instanceName, ResourceRecord::kTypeSrv))) { SuccessOrExit(error = AppendSrvRecord(aResponseMessage, instanceName, hostName, instanceTtl, - service->GetPriority(), service->GetWeight(), - service->GetPort(), aCompressInfo)); + service.GetPriority(), service.GetWeight(), service.GetPort(), + aCompressInfo)); IncResourceRecordCount(aResponseHeader, aAdditional); response = Header::kResponseSuccess; } @@ -808,8 +823,8 @@ Header::Response Server::ResolveQuestionBySrp(const char *aName, (aAdditional && ptrQueryMatched && !HasQuestion(aResponseHeader, aResponseMessage, instanceName, ResourceRecord::kTypeTxt))) { - SuccessOrExit(error = AppendTxtRecord(aResponseMessage, instanceName, service->GetTxtData(), - service->GetTxtDataLength(), instanceTtl, aCompressInfo)); + SuccessOrExit(error = AppendTxtRecord(aResponseMessage, instanceName, service.GetTxtData(), + service.GetTxtDataLength(), instanceTtl, aCompressInfo)); IncResourceRecordCount(aResponseHeader, aAdditional); response = Header::kResponseSuccess; } @@ -817,13 +832,13 @@ Header::Response Server::ResolveQuestionBySrp(const char *aName, } // Handle AAAA query - if ((!aAdditional && qtype == ResourceRecord::kTypeAaaa && host->Matches(aName)) || + if ((!aAdditional && qtype == ResourceRecord::kTypeAaaa && host.Matches(aName)) || (aAdditional && needAdditionalAaaaRecord && !HasQuestion(aResponseHeader, aResponseMessage, hostName, ResourceRecord::kTypeAaaa))) { uint8_t addrNum; - const Ip6::Address *addrs = host->GetAddresses(addrNum); - uint32_t hostTtl = TimeMilli::MsecToSec(host->GetExpireTime() - now); + const Ip6::Address *addrs = host.GetAddresses(addrNum); + uint32_t hostTtl = TimeMilli::MsecToSec(host.GetExpireTime() - now); for (uint8_t i = 0; i < addrNum; i++) { @@ -839,23 +854,6 @@ exit: return error == kErrorNone ? response : Header::kResponseServerFailure; } -const Srp::Server::Host *Server::GetNextSrpHost(const Srp::Server::Host *aHost) -{ - const Srp::Server::Host *host = Get().GetNextHost(aHost); - - while (host != nullptr && host->IsDeleted()) - { - host = Get().GetNextHost(host); - } - - return host; -} - -const Srp::Server::Service *Server::GetNextSrpService(const Srp::Server::Host &aHost, - const Srp::Server::Service *aService) -{ - return aHost.FindNextService(aService, Srp::Server::kFlagsAnyTypeActiveService); -} #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE Error Server::ResolveByQueryCallbacks(Header &aResponseHeader, diff --git a/src/core/net/dnssd_server.hpp b/src/core/net/dnssd_server.hpp index 88c737626..5991e99d7 100644 --- a/src/core/net/dnssd_server.hpp +++ b/src/core/net/dnssd_server.hpp @@ -485,18 +485,15 @@ private: const Ip6::MessageInfo &aMessageInfo, Ip6::Udp::Socket &aSocket); #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE - Header::Response ResolveBySrp(Header &aResponseHeader, - Message &aResponseMessage, - Server::NameCompressInfo &aCompressInfo); - Header::Response ResolveQuestionBySrp(const char *aName, - const Question &aQuestion, - Header &aResponseHeader, - Message &aResponseMessage, - NameCompressInfo &aCompressInfo, - bool aAdditional); - const Srp::Server::Host *GetNextSrpHost(const Srp::Server::Host *aHost); - static const Srp::Server::Service *GetNextSrpService(const Srp::Server::Host &aHost, - const Srp::Server::Service *aService); + Header::Response ResolveBySrp(Header &aResponseHeader, + Message &aResponseMessage, + Server::NameCompressInfo &aCompressInfo); + Header::Response ResolveQuestionBySrp(const char *aName, + const Question &aQuestion, + Header &aResponseHeader, + Message &aResponseMessage, + NameCompressInfo &aCompressInfo, + bool aAdditional); #endif #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index 9699d84ae..e908f68df 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -308,15 +308,6 @@ const Server::Host *Server::GetNextHost(const Server::Host *aHost) return (aHost == nullptr) ? mHosts.GetHead() : aHost->GetNext(); } -// This method adds a SRP service host and takes ownership of it. -// The caller MUST make sure that there is no existing host with the same hostname. -void Server::AddHost(Host &aHost) -{ - LogInfo("Add new host %s", aHost.GetFullName()); - - OT_ASSERT(mHosts.FindMatching(aHost.GetFullName()) == nullptr); - IgnoreError(mHosts.Add(aHost)); -} void Server::RemoveHost(Host *aHost, RetainName aRetainName, NotifyMode aNotifyServiceHandler) { VerifyOrExit(aHost != nullptr); @@ -376,7 +367,7 @@ bool Server::HasNameConflictsWith(Host &aHost) const for (const Host &host : mHosts) { - if (host.HasServiceInstance(service.GetInstanceName()) && + if (host.HasService(service.GetInstanceName()) && aHost.GetKeyRecord()->GetKey() != host.GetKeyRecord()->GetKey()) { LogWarn("Name conflict: service name %s has already been allocated", service.GetInstanceName()); @@ -442,15 +433,18 @@ void Server::CommitSrpUpdate(Error aError, const TtlConfig &aTtlConfig, const LeaseConfig &aLeaseConfig) { - Host *existingHost; - uint32_t grantedTtl; + Host *existingHost = nullptr; + uint32_t grantedTtl = 0; uint32_t hostLease = 0; uint32_t hostKeyLease = 0; uint32_t grantedLease = 0; uint32_t grantedKeyLease = 0; - bool shouldFreeHost = true; - SuccessOrExit(aError); + if (aError != kErrorNone) + { + aHost.Free(); + ExitNow(); + } hostLease = aHost.GetLease(); hostKeyLease = aHost.GetKeyLease(); @@ -458,66 +452,86 @@ void Server::CommitSrpUpdate(Error aError, grantedKeyLease = aHost.ShouldUseShortLeaseOption() ? grantedLease : aLeaseConfig.GrantKeyLease(hostKeyLease); grantedTtl = aTtlConfig.GrantTtl(grantedLease, aHost.GetTtl()); + existingHost = mHosts.RemoveMatching(aHost.GetFullName()); + + LogInfo("Committing update for %s host %s", (existingHost != nullptr) ? "existing" : "new", aHost.GetFullName()); + LogInfo(" Granted lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(grantedLease), ToUlong(grantedKeyLease), + ToUlong(grantedTtl)); + aHost.SetLease(grantedLease); aHost.SetKeyLease(grantedKeyLease); aHost.SetTtl(grantedTtl); + if (grantedKeyLease == 0) + { + VerifyOrExit(existingHost != nullptr); + LogInfo("Fully remove host %s", aHost.GetFullName()); + ExitNow(); + } + + mHosts.Push(aHost); + for (Service &service : aHost.mServices) { - service.mDescription->mLease = grantedLease; - service.mDescription->mKeyLease = grantedKeyLease; - service.mDescription->mTtl = grantedTtl; - } + service.mLease = grantedLease; + service.mKeyLease = grantedKeyLease; + service.mTtl = grantedTtl; + service.mIsCommitted = true; - existingHost = mHosts.FindMatching(aHost.GetFullName()); - - if (aHost.GetLease() == 0) - { - if (aHost.GetKeyLease() == 0) +#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) { - LogInfo("Remove key of host %s", aHost.GetFullName()); - RemoveHost(existingHost, kDeleteName, kDoNotNotifyServiceHandler); - } - else if (existingHost != nullptr) - { - existingHost->SetKeyLease(aHost.GetKeyLease()); - RemoveHost(existingHost, kRetainName, kDoNotNotifyServiceHandler); + Service::Action action = Service::kAddNew; - for (Service &service : existingHost->mServices) + if (service.mIsDeleted) { - existingHost->RemoveService(&service, kRetainName, kDoNotNotifyServiceHandler); + action = Service::kRemoveButRetainName; + } + else if ((existingHost != nullptr) && existingHost->HasService(service.GetInstanceName())) + { + action = Service::kUpdateExisting; } - } - } - else if (existingHost != nullptr) - { - SuccessOrExit(aError = existingHost->MergeServicesAndResourcesFrom(aHost)); - } - else - { - AddHost(aHost); - shouldFreeHost = false; - for (Service &service : aHost.GetServices()) - { - service.mIsCommitted = true; - service.Log(Service::kAddNew); - } - -#if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE - if (!mHasRegisteredAnyService && (mAddressMode == kAddressModeUnicast)) - { - Settings::SrpServerInfo info; - - mHasRegisteredAnyService = true; - info.SetPort(GetSocket().mSockName.mPort); - IgnoreError(Get().Save(info)); + service.Log(action); } #endif } - // Re-schedule the lease timer. - HandleLeaseTimer(); + if (existingHost != nullptr) + { + // Move any existing service that is not included in the new + // update into `aHost`. + + Service *existingService; + + while ((existingService = existingHost->mServices.Pop()) != nullptr) + { + if (!aHost.HasService(existingService->GetInstanceName())) + { + aHost.AddService(*existingService); + existingService->Log(Service::kKeepUnchanged); + } + else + { + existingService->Free(); + } + } + } + +#if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE + if (!mHasRegisteredAnyService && (mAddressMode == kAddressModeUnicast)) + { + Settings::SrpServerInfo info; + + mHasRegisteredAnyService = true; + info.SetPort(GetSocket().mSockName.mPort); + IgnoreError(Get().Save(info)); + } +#endif + + if (!aHost.IsDeleted()) + { + mLeaseTimer.FireAtIfEarlier(Min(aHost.GetExpireTime(), aHost.GetKeyExpireTime())); + } exit: if (aMessageInfo != nullptr) @@ -532,9 +546,9 @@ exit: } } - if (shouldFreeHost) + if (existingHost != nullptr) { - aHost.Free(); + existingHost->Free(); } } @@ -746,8 +760,6 @@ void Server::ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata) // Parse lease time and validate signature. SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aMetadata)); - SuccessOrExit(error = ValidateServiceSubTypes(*host, aMetadata)); - HandleUpdate(*host, aMetadata); exit: @@ -846,7 +858,7 @@ Error Server::ProcessHostDescriptionInstruction(Host &aHost, // A "Delete All RRsets from a name" RR can only apply to a Service or Host Description. - if (!aHost.HasServiceInstance(name)) + if (!aHost.HasService(name)) { // If host name is already set to a different name, `SetFullName()` // will return `kErrorFailed`. @@ -924,6 +936,7 @@ Error Server::ProcessServiceDiscoveryInstructions(Host &aHost, const char *subServiceName; Service *service; bool isSubType; + bool isDelete; SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, serviceName, sizeof(serviceName))); VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity); @@ -944,11 +957,12 @@ Error Server::ProcessServiceDiscoveryInstructions(Host &aHost, instanceServiceName, sizeof(instanceServiceName))); instanceName.Append("%s.%s", instanceLabel, instanceServiceName); - VerifyOrExit(ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone || - ptrRecord.GetClass() == aMetadata.mDnsZone.GetClass(), - error = kErrorFailed); + // Class None indicates "Delete an RR from an RRset". + isDelete = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone); - // Check if the `serviceName` is a subtype with the name + VerifyOrExit(isDelete || ptrRecord.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorParse); + + // Check if the `serviceName` is a sub-type with name // format: "._sub..." subServiceName = StringFind(serviceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch); @@ -965,22 +979,61 @@ Error Server::ProcessServiceDiscoveryInstructions(Host &aHost, VerifyOrExit(Dns::Name::IsSubDomainOf(instanceName.AsCString(), isSubType ? subServiceName : serviceName), error = kErrorFailed); - // Ensure the same service does not exist already. - VerifyOrExit(aHost.FindService(serviceName, instanceName.AsCString()) == nullptr, error = kErrorFailed); + // Find a matching existing service or allocate a new one. - service = - aHost.AddNewService(serviceName, instanceName.AsCString(), instanceLabel, isSubType, aMetadata.mRxTime); - VerifyOrExit(service != nullptr, error = kErrorNoBufs); + service = aHost.FindService(instanceName.AsCString()); - // This RR is a "Delete an RR from an RRset" update when the CLASS is NONE. - service->mIsDeleted = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone); + if (service == nullptr) + { + service = aHost.AddNewService(instanceName.AsCString(), instanceLabel, aMetadata.mRxTime); + VerifyOrExit(service != nullptr, error = kErrorNoBufs); + } - if (!service->mIsDeleted) + if (isSubType) + { + VerifyOrExit(!service->HasSubTypeServiceName(serviceName), error = kErrorFailed); + + // Ignore a sub-type service delete. + + if (!isDelete) + { + Heap::String *newSubTypeLabel = service->mSubTypes.PushBack(); + + VerifyOrExit(newSubTypeLabel != nullptr, error = kErrorNoBufs); + SuccessOrExit(error = newSubTypeLabel->Set(serviceName)); + } + } + else + { + // Processed PTR record is the base service (not a + // sub-type). `mServiceName` is only set when base + // service is processed. + + VerifyOrExit(service->mServiceName.IsNull(), error = kErrorFailed); + SuccessOrExit(error = service->mServiceName.Set(serviceName)); + service->mIsDeleted = isDelete; + } + + if (!isDelete) { SuccessOrExit(error = aHost.ProcessTtl(ptrRecord.GetTtl())); } } + // Verify that for all services, a PTR record was processed for + // the base service (`mServiceName` is set), and for a deleted + // service, no PTR record was seen adding a sub-type. + + for (const Service &service : aHost.mServices) + { + VerifyOrExit(!service.mServiceName.IsNull(), error = kErrorParse); + + if (service.mIsDeleted) + { + VerifyOrExit(service.mSubTypes.GetLength() == 0, error = kErrorParse); + } + } + exit: if (error != kErrorNone) { @@ -999,9 +1052,9 @@ Error Server::ProcessServiceDescriptionInstructions(Host &aHost, for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) { - RetainPtr desc; - char name[Dns::Name::kMaxNameSize]; - Dns::ResourceRecord record; + char name[Dns::Name::kMaxNameSize]; + Dns::ResourceRecord record; + Service *service; SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); SuccessOrExit(error = aMessage.Read(offset, record)); @@ -1011,12 +1064,12 @@ Error Server::ProcessServiceDescriptionInstructions(Host &aHost, // Delete All RRsets from a name. VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed); - desc = aHost.FindServiceDescription(name); + service = aHost.FindService(name); - if (desc != nullptr) + if (service != nullptr) { - desc->ClearResources(); - desc->mUpdateTime = aMetadata.mRxTime; + VerifyOrExit(!service->mParsedDeleteAllRrset); + service->mParsedDeleteAllRrset = true; } offset += record.GetSize(); @@ -1040,16 +1093,16 @@ Error Server::ProcessServiceDescriptionInstructions(Host &aHost, VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity); VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed); - desc = aHost.FindServiceDescription(name); - VerifyOrExit(desc != nullptr, error = kErrorFailed); + service = aHost.FindService(name); + VerifyOrExit(service != nullptr, error = kErrorFailed); - // Make sure that this is the first SRV RR for this service description - VerifyOrExit(desc->mPort == 0, error = kErrorFailed); - desc->mTtl = srvRecord.GetTtl(); - desc->mPriority = srvRecord.GetPriority(); - desc->mWeight = srvRecord.GetWeight(); - desc->mPort = srvRecord.GetPort(); - desc->mUpdateTime = aMetadata.mRxTime; + VerifyOrExit(!service->mParsedSrv, error = kErrorParse); + service->mParsedSrv = true; + + service->mTtl = srvRecord.GetTtl(); + service->mPriority = srvRecord.GetPriority(); + service->mWeight = srvRecord.GetWeight(); + service->mPort = srvRecord.GetPort(); } else if (record.GetType() == Dns::ResourceRecord::kTypeTxt) { @@ -1057,11 +1110,13 @@ Error Server::ProcessServiceDescriptionInstructions(Host &aHost, SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl())); - desc = aHost.FindServiceDescription(name); - VerifyOrExit(desc != nullptr, error = kErrorFailed); + service = aHost.FindService(name); + VerifyOrExit(service != nullptr, error = kErrorFailed); + + service->mParsedTxt = true; offset += sizeof(record); - SuccessOrExit(error = desc->SetTxtDataFromMessage(aMessage, offset, record.GetLength())); + SuccessOrExit(error = service->SetTxtDataFromMessage(aMessage, offset, record.GetLength())); offset += record.GetLength(); } else @@ -1070,20 +1125,15 @@ Error Server::ProcessServiceDescriptionInstructions(Host &aHost, } } - // Verify that all service descriptions on `aHost` are updated. Note - // that `mUpdateTime` on a new `Service::Description` is set to - // `GetNow().GetDistantPast()`. - - for (Service &service : aHost.mServices) + for (const Service &service : aHost.mServices) { - VerifyOrExit(service.mDescription->mUpdateTime == aMetadata.mRxTime, error = kErrorFailed); + VerifyOrExit(service.mParsedDeleteAllRrset, error = kErrorFailed); + VerifyOrExit(service.mParsedSrv == service.mParsedTxt, error = kErrorFailed); - // Check that either both `mPort` and `mTxtData` are set - // (i.e., we saw both SRV and TXT record) or both are default - // (cleared) value (i.e., we saw neither of them). - - VerifyOrExit((service.mDescription->mPort == 0) == service.mDescription->mTxtData.IsNull(), - error = kErrorFailed); + if (!service.mIsDeleted) + { + VerifyOrExit(service.mParsedSrv, error = kErrorFailed); + } } aMetadata.mOffset = offset; @@ -1235,68 +1285,6 @@ exit: return error; } -Error Server::ValidateServiceSubTypes(Host &aHost, const MessageMetadata &aMetadata) -{ - Error error = kErrorNone; - Host *existingHost; - - // Verify that there is a matching base type service for all - // sub-type services in `aHost` (which is from the received - // and parsed SRP Update message). - - for (const Service &service : aHost.GetServices()) - { - if (service.IsSubType() && (aHost.FindBaseService(service.GetInstanceName()) == nullptr)) - { -#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) - char subLabel[Dns::Name::kMaxLabelSize]; - - IgnoreError(service.GetServiceSubTypeLabel(subLabel, sizeof(subLabel))); - LogWarn("Message contains instance %s with subtype %s without base type", service.GetInstanceName(), - subLabel); -#endif - - ExitNow(error = kErrorParse); - } - } - - // SRP server must treat the update instructions for a service type - // and all its sub-types as atomic, i.e., when a service and its - // sub-types are being updated, whatever information appears in the - // SRP Update is the entirety of information about that service and - // its sub-types. Any previously registered sub-type that does not - // appear in a new SRP Update, must be removed. - // - // We go though the list of registered services for the same host - // and if the base service is included in the new SRP Update - // message, we add any previously registered service sub-type that - // does not appear in new Update message as "deleted". - - existingHost = mHosts.FindMatching(aHost.GetFullName()); - VerifyOrExit(existingHost != nullptr); - - for (const Service &baseService : existingHost->GetServices()) - { - if (baseService.IsSubType() || (aHost.FindBaseService(baseService.GetInstanceName()) == nullptr)) - { - continue; - } - - for (const Service &subService : existingHost->GetServices()) - { - if (!subService.IsSubType() || !subService.MatchesInstanceName(baseService.GetInstanceName())) - { - continue; - } - - SuccessOrExit(error = aHost.AddCopyOfServiceAsDeletedIfNotPresent(subService, aMetadata.mRxTime)); - } - } - -exit: - return error; -} - void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata) { Error error = kErrorNone; @@ -1315,14 +1303,21 @@ void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata) // when removing a host. We copy and append any missing services to // `aHost` from the `existingHost` and mark them as deleted. - for (Service &service : existingHost->mServices) + for (const Service &existingService : existingHost->mServices) { - if (service.mIsDeleted) + Service *service; + + if (existingService.mIsDeleted || aHost.HasService(existingService.GetInstanceName())) { continue; } - SuccessOrExit(error = aHost.AddCopyOfServiceAsDeletedIfNotPresent(service, aMetadata.mRxTime)); + service = aHost.AddNewService(existingService.GetInstanceName(), existingService.GetInstanceLabel(), + aMetadata.mRxTime); + VerifyOrExit(service != nullptr, error = kErrorNoBufs); + + SuccessOrExit(error = service->mServiceName.Set(existingService.GetServiceName())); + service->mIsDeleted = true; } exit: @@ -1337,7 +1332,7 @@ void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const Messag uint8_t numAddrs; const Ip6::Address *addrs; - LogInfo("Processed DNS update info"); + LogInfo("Processed SRP update info"); LogInfo(" Host:%s", aHost.GetFullName()); LogInfo(" Lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(aHost.GetLease()), ToUlong(aHost.GetKeyLease()), ToUlong(aHost.GetTtl())); @@ -1358,19 +1353,22 @@ void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const Messag } } - for (const Service &service : aHost.GetServices()) + for (const Service &service : aHost.mServices) { - char subLabel[Dns::Name::kMaxLabelSize]; + LogInfo(" %s service '%s'", service.IsDeleted() ? "Deleting" : "Adding", service.GetInstanceName()); - IgnoreError(service.GetServiceSubTypeLabel(subLabel, sizeof(subLabel))); + for (const Heap::String &subType : service.mSubTypes) + { + char label[Dns::Name::kMaxLabelSize]; - LogInfo(" %s service '%s'%s%s", service.IsDeleted() ? "Deleting" : "Adding", service.GetInstanceName(), - service.IsSubType() ? " subtype:" : "", subLabel); + IgnoreError(Service::ParseSubTypeServiceName(subType.AsCString(), label, sizeof(label))); + LogInfo(" sub-type: %s", label); + } } } else { - LogInfo("Error %s processing received DNS update", ErrorToString(aError)); + LogInfo("Error %s processing received SRP update", ErrorToString(aError)); } #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) @@ -1705,43 +1703,63 @@ void Server::UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode) //--------------------------------------------------------------------------------------------------------------------- // Server::Service -Error Server::Service::Init(const char *aServiceName, Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime) +Error Server::Service::Init(const char *aInstanceName, const char *aInstanceLabel, Host &aHost, TimeMilli aUpdateTime) { - mDescription.Reset(&aDescription); + Error error; + mNext = nullptr; + mHost = &aHost; + mPriority = 0; + mWeight = 0; + mTtl = 0; + mPort = 0; + mLease = 0; + mKeyLease = 0; mUpdateTime = aUpdateTime; mIsDeleted = false; - mIsSubType = aIsSubType; mIsCommitted = false; - return mServiceName.Set(aServiceName); + mParsedDeleteAllRrset = false; + mParsedSrv = false; + mParsedTxt = false; + + SuccessOrExit(error = mInstanceLabel.Set(aInstanceLabel)); + error = mInstanceName.Set(aInstanceName); + +exit: + return error; } -Error Server::Service::GetServiceSubTypeLabel(char *aLabel, uint8_t aMaxSize) const +const char *Server::Service::GetSubTypeServiceNameAt(uint16_t aIndex) const { - Error error = kErrorNone; - const char *serviceName = GetServiceName(); - const char *subServiceName; + const Heap::String *subType = mSubTypes.At(aIndex); + + return (subType == nullptr) ? nullptr : subType->AsCString(); +} + +Error Server::Service::ParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize) +{ + Error error = kErrorNone; + const char *subPos; uint8_t labelLength; - memset(aLabel, 0, aMaxSize); + aLabel[0] = kNullChar; - VerifyOrExit(IsSubType(), error = kErrorInvalidArgs); + subPos = StringFind(aSubTypeServiceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch); + VerifyOrExit(subPos != nullptr, error = kErrorInvalidArgs); - subServiceName = StringFind(serviceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch); - OT_ASSERT(subServiceName != nullptr); - - if (subServiceName - serviceName < aMaxSize) + if (subPos - aSubTypeServiceName < aLabelSize) { - labelLength = static_cast(subServiceName - serviceName); + labelLength = static_cast(subPos - aSubTypeServiceName); } else { - labelLength = aMaxSize - 1; + labelLength = aLabelSize - 1; error = kErrorNoBufs; } - memcpy(aLabel, serviceName, labelLength); + memcpy(aLabel, aSubTypeServiceName, labelLength); + aLabel[labelLength] = kNullChar; exit: return error; @@ -1752,13 +1770,10 @@ TimeMilli Server::Service::GetExpireTime(void) const OT_ASSERT(!mIsDeleted); OT_ASSERT(!GetHost().IsDeleted()); - return mUpdateTime + Time::SecToMsec(mDescription->mLease); + return mUpdateTime + Time::SecToMsec(mLease); } -TimeMilli Server::Service::GetKeyExpireTime(void) const -{ - return mUpdateTime + Time::SecToMsec(mDescription->mKeyLease); -} +TimeMilli Server::Service::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); } void Server::Service::GetLeaseInfo(LeaseInfo &aLeaseInfo) const { @@ -1781,42 +1796,32 @@ void Server::Service::GetLeaseInfo(LeaseInfo &aLeaseInfo) const } } -bool Server::Service::MatchesInstanceName(const char *aInstanceName) const -{ - return StringMatch(mDescription->mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch); -} +bool Server::Service::MatchesInstanceName(const char *aInstanceName) const { return Matches(aInstanceName); } bool Server::Service::MatchesServiceName(const char *aServiceName) const { return StringMatch(mServiceName.AsCString(), aServiceName, kStringCaseInsensitiveMatch); } -bool Server::Service::MatchesFlags(Flags aFlags) const +bool Server::Service::Matches(const char *aInstanceName) const { - bool matches = false; + return StringMatch(mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch); +} - if (IsSubType()) +bool Server::Service::HasSubTypeServiceName(const char *aSubTypeServiceName) const +{ + bool has = false; + + for (const Heap::String &subType : mSubTypes) { - VerifyOrExit(aFlags & kFlagSubType); - } - else - { - VerifyOrExit(aFlags & kFlagBaseType); + if (StringMatch(subType.AsCString(), aSubTypeServiceName, kStringCaseInsensitiveMatch)) + { + has = true; + break; + } } - if (IsDeleted()) - { - VerifyOrExit(aFlags & kFlagDeleted); - } - else - { - VerifyOrExit(aFlags & kFlagActive); - } - - matches = true; - -exit: - return matches; + return has; } #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) @@ -1825,20 +1830,20 @@ void Server::Service::Log(Action aAction) const static const char *const kActionStrings[] = { "Add new", // (0) kAddNew "Update existing", // (1) kUpdateExisting - "Remove but retain name of", // (2) kRemoveButRetainName - "Fully remove", // (3) kFullyRemove - "LEASE expired for", // (4) kLeaseExpired - "KEY LEASE expired for", // (5) kKeyLeaseExpired + "Keep unchanged", // (2) kKeepUnchanged + "Remove but retain name of", // (3) kRemoveButRetainName + "Fully remove", // (4) kFullyRemove + "LEASE expired for", // (5) kLeaseExpired + "KEY LEASE expired for", // (6) kKeyLeaseExpired }; - char subLabel[Dns::Name::kMaxLabelSize]; - static_assert(0 == kAddNew, "kAddNew value is incorrect"); static_assert(1 == kUpdateExisting, "kUpdateExisting value is incorrect"); - static_assert(2 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect"); - static_assert(3 == kFullyRemove, "kFullyRemove value is incorrect"); - static_assert(4 == kLeaseExpired, "kLeaseExpired value is incorrect"); - static_assert(5 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect"); + static_assert(2 == kKeepUnchanged, "kKeepUnchanged value is incorrect"); + static_assert(3 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect"); + static_assert(4 == kFullyRemove, "kFullyRemove value is incorrect"); + static_assert(5 == kLeaseExpired, "kLeaseExpired value is incorrect"); + static_assert(6 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect"); // We only log if the `Service` is marked as committed. This // ensures that temporary `Service` entries associated with a @@ -1847,67 +1852,22 @@ void Server::Service::Log(Action aAction) const if (mIsCommitted) { - IgnoreError(GetServiceSubTypeLabel(subLabel, sizeof(subLabel))); + LogInfo("%s service '%s'", kActionStrings[aAction], GetInstanceName()); - LogInfo("%s service '%s'%s%s", kActionStrings[aAction], GetInstanceName(), IsSubType() ? " subtype:" : "", - subLabel); + for (const Heap::String &subType : mSubTypes) + { + char label[Dns::Name::kMaxLabelSize]; + + IgnoreError(ParseSubTypeServiceName(subType.AsCString(), label, sizeof(label))); + LogInfo(" sub-type: %s", subType.AsCString()); + } } } #else void Server::Service::Log(Action) const {} #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) -//--------------------------------------------------------------------------------------------------------------------- -// Server::Service::Description - -Error Server::Service::Description::Init(const char *aInstanceName, const char *aInstanceLabel, Host &aHost) -{ - Error error; - - mNext = nullptr; - mHost = &aHost; - mPriority = 0; - mWeight = 0; - mTtl = 0; - mPort = 0; - mLease = 0; - mKeyLease = 0; - mUpdateTime = TimerMilli::GetNow().GetDistantPast(); - mTxtData.Free(); - - SuccessOrExit(error = mInstanceLabel.Set(aInstanceLabel)); - error = mInstanceName.Set(aInstanceName); - -exit: - return error; -} - -bool Server::Service::Description::Matches(const char *aInstanceName) const -{ - return StringMatch(mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch); -} - -void Server::Service::Description::ClearResources(void) -{ - mPort = 0; - mTxtData.Free(); -} - -void Server::Service::Description::TakeResourcesFrom(Description &aDescription) -{ - mTxtData.SetFrom(static_cast(aDescription.mTxtData)); - - mPriority = aDescription.mPriority; - mWeight = aDescription.mWeight; - mPort = aDescription.mPort; - - mTtl = aDescription.mTtl; - mLease = aDescription.mLease; - mKeyLease = aDescription.mKeyLease; - mUpdateTime = TimerMilli::GetNow(); -} - -Error Server::Service::Description::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength) +Error Server::Service::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength) { Error error; @@ -2022,64 +1982,28 @@ exit: return error; } -const Server::Service *Server::Host::FindNextService(const Service *aPrevService, - Service::Flags aFlags, - const char *aServiceName, - const char *aInstanceName) const +const Server::Service *Server::Host::GetNextService(const Service *aPrevService) const { - const Service *service = (aPrevService == nullptr) ? GetServices().GetHead() : aPrevService->GetNext(); - - for (; service != nullptr; service = service->GetNext()) - { - if (!service->MatchesFlags(aFlags)) - { - continue; - } - - if ((aServiceName != nullptr) && !service->MatchesServiceName(aServiceName)) - { - continue; - } - - if ((aInstanceName != nullptr) && !service->MatchesInstanceName(aInstanceName)) - { - continue; - } - - break; - } - - return service; + return (aPrevService == nullptr) ? mServices.GetHead() : aPrevService->GetNext(); } -Server::Service *Server::Host::AddNewService(const char *aServiceName, - const char *aInstanceName, +Server::Service *Server::Host::AddNewService(const char *aInstanceName, const char *aInstanceLabel, - bool aIsSubType, TimeMilli aUpdateTime) { - Service *service = nullptr; - RetainPtr desc(FindServiceDescription(aInstanceName)); + Service *service = Service::AllocateAndInit(aInstanceName, aInstanceLabel, *this, aUpdateTime); - if (desc == nullptr) - { - desc.Reset(Service::Description::AllocateAndInit(aInstanceName, aInstanceLabel, *this)); - VerifyOrExit(desc != nullptr); - } - - service = Service::AllocateAndInit(aServiceName, *desc, aIsSubType, aUpdateTime); VerifyOrExit(service != nullptr); - - mServices.Push(*service); + AddService(*service); exit: return service; } -Server::Service *Server::Host::AddNewService(const Service &aService, TimeMilli aUpdateTime) +void Server::Host::AddService(Service &aService) { - return AddNewService(aService.GetServiceName(), aService.GetInstanceName(), aService.GetInstanceLabel(), - aService.IsSubType(), aUpdateTime); + aService.mHost = this; + mServices.Push(aService); } void Server::Host::RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler) @@ -2115,24 +2039,6 @@ exit: return; } -Error Server::Host::AddCopyOfServiceAsDeletedIfNotPresent(const Service &aService, TimeMilli aUpdateTime) -{ - Error error = kErrorNone; - Service *newService; - - VerifyOrExit(FindService(aService.GetServiceName(), aService.GetInstanceName()) == nullptr); - - newService = AddNewService(aService, aUpdateTime); - - VerifyOrExit(newService != nullptr, error = kErrorNoBufs); - - newService->mDescription->mUpdateTime = aUpdateTime; - newService->mIsDeleted = true; - -exit: - return error; -} - void Server::Host::FreeAllServices(void) { while (!mServices.IsEmpty()) @@ -2143,106 +2049,14 @@ void Server::Host::FreeAllServices(void) void Server::Host::ClearResources(void) { mAddresses.Free(); } -Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost) +Server::Service *Server::Host::FindService(const char *aInstanceName) { return mServices.FindMatching(aInstanceName); } + +const Server::Service *Server::Host::FindService(const char *aInstanceName) const { - // This method merges services, service descriptions, and other - // resources from another `aHost` into current host. It can - // possibly take ownership of some items from `aHost`. - - Error error = kErrorNone; - - LogInfo("Update host %s", GetFullName()); - - mAddresses.TakeFrom(static_cast &&>(aHost.mAddresses)); - mKeyRecord = aHost.mKeyRecord; - mTtl = aHost.mTtl; - mLease = aHost.mLease; - mKeyLease = aHost.mKeyLease; - mUpdateTime = TimerMilli::GetNow(); - - for (Service &service : aHost.mServices) - { - Service *existingService = FindService(service.GetServiceName(), service.GetInstanceName()); - Service *newService; - - if (service.mIsDeleted) - { - // `RemoveService()` does nothing if `existingService` is `nullptr`. - RemoveService(existingService, kRetainName, kDoNotNotifyServiceHandler); - continue; - } - - // Add/Merge `service` into the existing service or a allocate a new one - - newService = (existingService != nullptr) ? existingService : AddNewService(service, service.GetUpdateTime()); - - VerifyOrExit(newService != nullptr, error = kErrorNoBufs); - - newService->mIsDeleted = false; - newService->mIsCommitted = true; - newService->mUpdateTime = TimerMilli::GetNow(); - - if (!service.mIsSubType) - { - // (1) Service description is shared across a base type and all its subtypes. - // (2) `TakeResourcesFrom()` releases resources pinned to its argument. - // Therefore, make sure the function is called only for the base type. - newService->mDescription->TakeResourcesFrom(*service.mDescription); - } - - newService->Log((existingService != nullptr) ? Service::kUpdateExisting : Service::kAddNew); - } - -exit: - return error; + return mServices.FindMatching(aInstanceName); } -bool Server::Host::HasServiceInstance(const char *aInstanceName) const -{ - return (FindServiceDescription(aInstanceName) != nullptr); -} - -const RetainPtr Server::Host::FindServiceDescription(const char *aInstanceName) const -{ - const Service::Description *desc = nullptr; - - for (const Service &service : mServices) - { - if (service.mDescription->Matches(aInstanceName)) - { - desc = service.mDescription.Get(); - break; - } - } - - return RetainPtr(AsNonConst(desc)); -} - -RetainPtr Server::Host::FindServiceDescription(const char *aInstanceName) -{ - return AsNonConst(AsConst(this)->FindServiceDescription(aInstanceName)); -} - -const Server::Service *Server::Host::FindService(const char *aServiceName, const char *aInstanceName) const -{ - return FindNextService(/* aPrevService */ nullptr, kFlagsAnyService, aServiceName, aInstanceName); -} - -Server::Service *Server::Host::FindService(const char *aServiceName, const char *aInstanceName) -{ - return AsNonConst(AsConst(this)->FindService(aServiceName, aInstanceName)); -} - -const Server::Service *Server::Host::FindBaseService(const char *aInstanceName) const -{ - return FindNextService(/*a PrevService */ nullptr, kFlagsBaseTypeServiceOnly, /* aServiceName */ nullptr, - aInstanceName); -} - -Server::Service *Server::Host::FindBaseService(const char *aInstanceName) -{ - return AsNonConst(AsConst(this)->FindBaseService(aInstanceName)); -} +bool Server::Host::HasService(const char *aInstanceName) const { return mServices.ContainsMatching(aInstanceName); } Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address) { diff --git a/src/core/net/srp_server.hpp b/src/core/net/srp_server.hpp index ba5665b0c..25d1f75cc 100644 --- a/src/core/net/srp_server.hpp +++ b/src/core/net/srp_server.hpp @@ -187,37 +187,6 @@ public: friend class Heap::Allocatable; public: - /** - * Represents the flags which indicates which services to include or exclude when searching in (or - * iterating over) the list of SRP services. - * - */ - typedef otSrpServerServiceFlags Flags; - - /** - * This `Flags` constant indicates to include base services (not a sub-type). - * - */ - static constexpr Flags kFlagBaseType = OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE; - - /** - * This `Flags` constant indicates to include sub-type services. - * - */ - static constexpr Flags kFlagSubType = OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE; - - /** - * This `Flags` constant indicates to include active (not deleted) services. - * - */ - static constexpr Flags kFlagActive = OT_SRP_SERVER_SERVICE_FLAG_ACTIVE; - - /** - * This `Flags` constant indicates to include deleted services. - * - */ - static constexpr Flags kFlagDeleted = OT_SRP_SERVER_SERVICE_FLAG_DELETED; - /** * Tells if the SRP service has been deleted. * @@ -230,22 +199,13 @@ public: */ bool IsDeleted(void) const { return mIsDeleted; } - /** - * Indicates whether the SRP service is a sub-type. - * - * @retval TRUE If the service is a sub-type. - * @retval FALSE If the service is not a sub-type. - * - */ - bool IsSubType(void) const { return mIsSubType; } - /** * Gets the full service instance name of the service. * * @returns A pointer service instance name (as a null-terminated C string). * */ - const char *GetInstanceName(void) const { return mDescription->GetInstanceName(); } + const char *GetInstanceName(void) const { return mInstanceName.AsCString(); } /** * Gets the service instance label of the service. @@ -253,7 +213,7 @@ public: * @returns A pointer service instance label (as a null-terminated C string). * */ - const char *GetInstanceLabel(void) const { return mDescription->GetInstanceLabel(); } + const char *GetInstanceLabel(void) const { return mInstanceLabel.AsCString(); } /** * Gets the full service name of the service. @@ -264,23 +224,52 @@ public: const char *GetServiceName(void) const { return mServiceName.AsCString(); } /** - * Gets the sub-type label from service name. + * Gets number of sub-types of this service. * - * The full service name for a sub-type service follows "._sub...". This - * method copies the `` into the @p aLabel buffer. - * - * The @p aLabel is ensured to always be null-terminated after returning even in case of failure. - * - * @param[out] aLabel A pointer to a buffer to copy the sub-type label name. - * @param[in] aMaxSize Maximum size of @p aLabel buffer. - * - * @retval kErrorNone @p aLabel was updated successfully. - * @retval kErrorNoBufs The sub-type label could not fit in @p aLabel buffer (number of chars from label - * that could fit are copied in @p aLabel ensuring it is null-terminated). - * @retval kErrorInvalidArgs SRP service is not a sub-type. + * @returns The number of sub-types. * */ - Error GetServiceSubTypeLabel(char *aLabel, uint8_t aMaxSize) const; + uint16_t GetNumberOfSubTypes(void) const { return mSubTypes.GetLength(); } + + /** + * Gets the sub-type service name (full name) at a given index. + * + * The full service name for a sub-type service follows "._sub...". + * + * @param[in] aIndex The index to get. + * + * @returns A pointer to sub-type service name at @p aIndex, or `nullptr` if none at this index. + * + */ + const char *GetSubTypeServiceNameAt(uint16_t aIndex) const; + + /** + * Indicates whether or not service has a given sub-type. + * + * @param[in] aSubTypeServiceName The sub-type service name (full name). + * + * @retval TRUE Service contains the sub-type @p aSubTypeServiceName. + * @retval FALSE Service does not contain the sub-type @p aSubTypeServiceName. + * + */ + bool HasSubTypeServiceName(const char *aSubTypeServiceName) const; + + /** + * Parses a sub-type service name (full name) and extracts the sub-type label. + * + * The full service name for a sub-type service follows "._sub...". + * + * @param[in] aSubTypeServiceName A sub-type service name (full name). + * @param[out] aLabel A pointer to a buffer to copy the extracted sub-type label. + * @param[in] aLabelSize Maximum size of @p aLabel buffer. + * + * @retval kErrorNone Name was successfully parsed and @p aLabel was updated. + * @retval kErrorNoBufs The sub-type label could not fit in @p aLabel buffer (number of chars from label + * that could fit are copied in @p aLabel ensuring it is null-terminated). + * @retval kErrorInvalidArgs @p aSubTypeServiceName is not a valid sub-type format. + * + */ + static Error ParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize); /** * Returns the TTL of the service instance. @@ -288,7 +277,7 @@ public: * @returns The TTL of the service instance. * */ - uint32_t GetTtl(void) const { return mDescription->mTtl; } + uint32_t GetTtl(void) const { return mTtl; } /** * Returns the port of the service instance. @@ -296,7 +285,7 @@ public: * @returns The port of the service. * */ - uint16_t GetPort(void) const { return mDescription->mPort; } + uint16_t GetPort(void) const { return mPort; } /** * Returns the weight of the service instance. @@ -304,7 +293,7 @@ public: * @returns The weight of the service. * */ - uint16_t GetWeight(void) const { return mDescription->mWeight; } + uint16_t GetWeight(void) const { return mWeight; } /** * Returns the priority of the service instance. @@ -312,7 +301,7 @@ public: * @returns The priority of the service. * */ - uint16_t GetPriority(void) const { return mDescription->mPriority; } + uint16_t GetPriority(void) const { return mPriority; } /** * Returns the TXT record data of the service instance. @@ -320,7 +309,7 @@ public: * @returns A pointer to the buffer containing the TXT record data. * */ - const uint8_t *GetTxtData(void) const { return mDescription->mTxtData.GetBytes(); } + const uint8_t *GetTxtData(void) const { return mTxtData.GetBytes(); } /** * Returns the TXT record data length of the service instance. @@ -328,7 +317,7 @@ public: * @return The TXT record data length (number of bytes in buffer returned from `GetTxtData()`). * */ - uint16_t GetTxtDataLength(void) const { return mDescription->mTxtData.GetLength(); } + uint16_t GetTxtDataLength(void) const { return mTxtData.GetLength(); } /** * Returns the host which the service instance reside on. @@ -336,7 +325,7 @@ public: * @returns A reference to the host instance. * */ - const Host &GetHost(void) const { return *mDescription->mHost; } + const Host &GetHost(void) const { return *mHost; } /** * Returns the LEASE time of the service. @@ -344,7 +333,7 @@ public: * @returns The LEASE time in seconds. * */ - uint32_t GetLease(void) const { return mDescription->mLease; } + uint32_t GetLease(void) const { return mLease; } /** * Returns the KEY-LEASE time of the key of the service. @@ -352,7 +341,7 @@ public: * @returns The KEY-LEASE time in seconds. * */ - uint32_t GetKeyLease(void) const { return mDescription->mKeyLease; } + uint32_t GetKeyLease(void) const { return mKeyLease; } /** * Returns the expire time (in milliseconds) of the service. @@ -402,55 +391,41 @@ public: bool MatchesServiceName(const char *aServiceName) const; private: - struct Description : public LinkedListEntry, - public Heap::Allocatable, - public RetainCountable, - private NonCopyable - { - Error Init(const char *aInstanceName, const char *aInstanceLabel, Host &aHost); - const char *GetInstanceName(void) const { return mInstanceName.AsCString(); } - const char *GetInstanceLabel(void) const { return mInstanceLabel.AsCString(); } - bool Matches(const char *aInstanceName) const; - void ClearResources(void); - void TakeResourcesFrom(Description &aDescription); - Error SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength); - - Description *mNext; - Heap::String mInstanceName; - Heap::String mInstanceLabel; - Host *mHost; - Heap::Data mTxtData; - uint16_t mPriority; - uint16_t mWeight; - uint16_t mPort; - uint32_t mTtl; // The TTL in seconds. - uint32_t mLease; // The LEASE time in seconds. - uint32_t mKeyLease; // The KEY-LEASE time in seconds. - TimeMilli mUpdateTime; - }; - enum Action : uint8_t { kAddNew, kUpdateExisting, + kKeepUnchanged, kRemoveButRetainName, kFullyRemove, kLeaseExpired, kKeyLeaseExpired, }; - Error Init(const char *aServiceName, Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime); - bool MatchesFlags(Flags aFlags) const; - const TimeMilli &GetUpdateTime(void) const { return mUpdateTime; } - void Log(Action aAction) const; + Error Init(const char *aInstanceName, const char *aInstanceLabel, Host &aHost, TimeMilli aUpdateTime); + Error SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength); + bool Matches(const char *aInstanceName) const; + void Log(Action aAction) const; - Heap::String mServiceName; - RetainPtr mDescription; - Service *mNext; - TimeMilli mUpdateTime; - bool mIsDeleted : 1; - bool mIsSubType : 1; - bool mIsCommitted : 1; + Service *mNext; + Heap::String mInstanceName; + Heap::String mInstanceLabel; + Heap::String mServiceName; + Heap::Array mSubTypes; + Host *mHost; + Heap::Data mTxtData; + uint16_t mPriority; + uint16_t mWeight; + uint16_t mPort; + uint32_t mTtl; // In seconds + uint32_t mLease; // In seconds + uint32_t mKeyLease; // In seconds + TimeMilli mUpdateTime; + bool mIsDeleted : 1; + bool mIsCommitted : 1; + bool mParsedDeleteAllRrset : 1; + bool mParsedSrv : 1; + bool mParsedTxt : 1; }; /** @@ -568,21 +543,15 @@ public: */ const LinkedList &GetServices(void) const { return mServices; } - /** - * Finds the next matching service on the host. + /* + * Returns the next service. * * @param[in] aPrevService A pointer to the previous service or `nullptr` to start from beginning of the list. - * @param[in] aFlags Flags indicating which services to include (base/sub-type, active/deleted). - * @param[in] aServiceName The service name to match. Set to `nullptr` to accept any name. - * @param[in] aInstanceName The service instance name to match. Set to `nullptr` to accept any name. * - * @returns A pointer to the next matching service or `nullptr` if no matching service could be found. + * @returns A pointer to the next service or `nullptr` if no more services can be found. * */ - const Service *FindNextService(const Service *aPrevService, - Service::Flags aFlags = kFlagsAnyService, - const char *aServiceName = nullptr, - const char *aInstanceName = nullptr) const; + const Service *GetNextService(const Service *aPrevService) const; /** * Tells whether the host matches a given full name. @@ -607,26 +576,15 @@ public: bool ShouldUseShortLeaseOption(void) const { return mUseShortLeaseOption; } Error ProcessTtl(uint32_t aTtl); - LinkedList &GetServices(void) { return mServices; } - Service *AddNewService(const char *aServiceName, - const char *aInstanceName, - const char *aInstanceLabel, - bool aIsSubType, - TimeMilli aUpdateTime); - Service *AddNewService(const Service &aService, TimeMilli aUpdateTime); - void RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler); - Error AddCopyOfServiceAsDeletedIfNotPresent(const Service &aService, TimeMilli aUpdateTime); - void FreeAllServices(void); - void ClearResources(void); - Error MergeServicesAndResourcesFrom(Host &aHost); - Error AddIp6Address(const Ip6::Address &aIp6Address); - bool HasServiceInstance(const char *aInstanceName) const; - RetainPtr FindServiceDescription(const char *aInstanceName); - const RetainPtr FindServiceDescription(const char *aInstanceName) const; - Service *FindService(const char *aServiceName, const char *aInstanceName); - const Service *FindService(const char *aServiceName, const char *aInstanceName) const; - Service *FindBaseService(const char *aInstanceName); - const Service *FindBaseService(const char *aInstanceName) const; + Service *AddNewService(const char *aInstanceName, const char *aInstanceLabel, TimeMilli aUpdateTime); + void AddService(Service &aService); + void RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler); + bool HasService(const char *aInstanceName) const; + Service *FindService(const char *aInstanceName); + const Service *FindService(const char *aInstanceName) const; + void FreeAllServices(void); + void ClearResources(void); + Error AddIp6Address(const Ip6::Address &aIp6Address); Host *mNext; Heap::String mFullName; @@ -684,36 +642,6 @@ public: uint32_t GrantKeyLease(uint32_t aKeyLease) const; }; - /** - * This constant defines a `Service::Flags` combination accepting any service (base/sub-type, active/deleted). - * - */ - static constexpr Service::Flags kFlagsAnyService = OT_SRP_SERVER_FLAGS_ANY_SERVICE; - - /** - * This constant defines a `Service::Flags` combination accepting base services only. - * - */ - static constexpr Service::Flags kFlagsBaseTypeServiceOnly = OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY; - - /** - * This constant defines a `Service::Flags` combination accepting sub-type services only. - * - */ - static constexpr Service::Flags kFlagsSubTypeServiceOnly = OT_SRP_SERVER_FLAGS_SUB_TYPE_SERVICE_ONLY; - - /** - * This constant defines a `Service::Flags` combination accepting any active services (not deleted). - * - */ - static constexpr Service::Flags kFlagsAnyTypeActiveService = OT_SRP_SERVER_FLAGS_ANY_TYPE_ACTIVE_SERVICE; - - /** - * This constant defines a `Service::Flags` combination accepting any deleted services. - * - */ - static constexpr Service::Flags kFlagsAnyTypeDeletedService = OT_SRP_SERVER_FLAGS_ANY_TYPE_DELETED_SERVICE; - /** * Initializes the SRP server object. * @@ -901,6 +829,14 @@ public: */ Error SetLeaseConfig(const LeaseConfig &aLeaseConfig); + /** + * Returns the `Host` linked list. + * + * @returns The `Host` linked list. + * + */ + const LinkedList &GetHosts(void) const { return mHosts; } + /** * Returns the next registered SRP host. * @@ -1037,7 +973,6 @@ private: uint16_t aSigRdataOffset, uint16_t aSigRdataLength, const char *aSignerName) const; - Error ValidateServiceSubTypes(Host &aHost, const MessageMetadata &aMetadata); Error ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const; Error ProcessHostDescriptionInstruction(Host &aHost, const Message &aMessage, @@ -1050,7 +985,6 @@ private: static bool IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord); void HandleUpdate(Host &aHost, const MessageMetadata &aMetadata); - void AddHost(Host &aHost); void RemoveHost(Host *aHost, RetainName aRetainName, NotifyMode aNotifyServiceHandler); bool HasNameConflictsWith(Host &aHost) const; void SendResponse(const Dns::UpdateHeader &aHeader,