| /* |
| * Copyright (c) 2020, 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 a simple CLI for the SRP server. |
| */ |
| |
| #include "cli_srp_server.hpp" |
| |
| #include <inttypes.h> |
| |
| #include "cli/cli.hpp" |
| #include "common/string.hpp" |
| |
| #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE |
| |
| namespace ot { |
| namespace Cli { |
| |
| template <> otError SrpServer::Process<Cmd("addrmode")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_INVALID_ARGS; |
| |
| if (aArgs[0].IsEmpty()) |
| { |
| switch (otSrpServerGetAddressMode(GetInstancePtr())) |
| { |
| case OT_SRP_SERVER_ADDRESS_MODE_UNICAST: |
| OutputLine("unicast"); |
| break; |
| |
| case OT_SRP_SERVER_ADDRESS_MODE_ANYCAST: |
| OutputLine("anycast"); |
| break; |
| } |
| |
| error = OT_ERROR_NONE; |
| } |
| else if (aArgs[0] == "unicast") |
| { |
| error = otSrpServerSetAddressMode(GetInstancePtr(), OT_SRP_SERVER_ADDRESS_MODE_UNICAST); |
| } |
| else if (aArgs[0] == "anycast") |
| { |
| error = otSrpServerSetAddressMode(GetInstancePtr(), OT_SRP_SERVER_ADDRESS_MODE_ANYCAST); |
| } |
| |
| return error; |
| } |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE |
| /** |
| * @cli srp server auto |
| * @code |
| * srp server auto |
| * Disabled |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otSrpServerIsAutoEnableMode |
| */ |
| template <> otError SrpServer::Process<Cmd("auto")>(Arg aArgs[]) |
| { |
| /** |
| * @cli srp server auto enable |
| * @code |
| * srp server auto enable |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otSrpServerSetAutoEnableMode |
| */ |
| return Interpreter::GetInterpreter().ProcessEnableDisable(aArgs, otSrpServerIsAutoEnableMode, |
| otSrpServerSetAutoEnableMode); |
| } |
| #endif |
| |
| template <> otError SrpServer::Process<Cmd("domain")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| if (aArgs[0].IsEmpty()) |
| { |
| OutputLine("%s", otSrpServerGetDomain(GetInstancePtr())); |
| } |
| else |
| { |
| error = otSrpServerSetDomain(GetInstancePtr(), aArgs[0].GetCString()); |
| } |
| |
| return error; |
| } |
| |
| template <> otError SrpServer::Process<Cmd("state")>(Arg aArgs[]) |
| { |
| static const char *const kStateStrings[] = { |
| "disabled", // (0) OT_SRP_SERVER_STATE_DISABLED |
| "running", // (1) OT_SRP_SERVER_STATE_RUNNING |
| "stopped", // (2) OT_SRP_SERVER_STATE_STOPPED |
| }; |
| |
| OT_UNUSED_VARIABLE(aArgs); |
| |
| static_assert(0 == OT_SRP_SERVER_STATE_DISABLED, "OT_SRP_SERVER_STATE_DISABLED value is incorrect"); |
| static_assert(1 == OT_SRP_SERVER_STATE_RUNNING, "OT_SRP_SERVER_STATE_RUNNING value is incorrect"); |
| static_assert(2 == OT_SRP_SERVER_STATE_STOPPED, "OT_SRP_SERVER_STATE_STOPPED value is incorrect"); |
| |
| OutputLine("%s", Stringify(otSrpServerGetState(GetInstancePtr()), kStateStrings)); |
| |
| return OT_ERROR_NONE; |
| } |
| |
| template <> otError SrpServer::Process<Cmd("enable")>(Arg aArgs[]) |
| { |
| OT_UNUSED_VARIABLE(aArgs); |
| |
| otSrpServerSetEnabled(GetInstancePtr(), /* aEnabled */ true); |
| |
| return OT_ERROR_NONE; |
| } |
| |
| template <> otError SrpServer::Process<Cmd("disable")>(Arg aArgs[]) |
| { |
| OT_UNUSED_VARIABLE(aArgs); |
| |
| otSrpServerSetEnabled(GetInstancePtr(), /* aEnabled */ false); |
| |
| return OT_ERROR_NONE; |
| } |
| |
| template <> otError SrpServer::Process<Cmd("ttl")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| otSrpServerTtlConfig ttlConfig; |
| |
| if (aArgs[0].IsEmpty()) |
| { |
| otSrpServerGetTtlConfig(GetInstancePtr(), &ttlConfig); |
| OutputLine("min ttl: %lu", ToUlong(ttlConfig.mMinTtl)); |
| OutputLine("max ttl: %lu", ToUlong(ttlConfig.mMaxTtl)); |
| } |
| else |
| { |
| SuccessOrExit(error = aArgs[0].ParseAsUint32(ttlConfig.mMinTtl)); |
| SuccessOrExit(error = aArgs[1].ParseAsUint32(ttlConfig.mMaxTtl)); |
| VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| error = otSrpServerSetTtlConfig(GetInstancePtr(), &ttlConfig); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError SrpServer::Process<Cmd("lease")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| otSrpServerLeaseConfig leaseConfig; |
| |
| if (aArgs[0].IsEmpty()) |
| { |
| otSrpServerGetLeaseConfig(GetInstancePtr(), &leaseConfig); |
| OutputLine("min lease: %lu", ToUlong(leaseConfig.mMinLease)); |
| OutputLine("max lease: %lu", ToUlong(leaseConfig.mMaxLease)); |
| OutputLine("min key-lease: %lu", ToUlong(leaseConfig.mMinKeyLease)); |
| OutputLine("max key-lease: %lu", ToUlong(leaseConfig.mMaxKeyLease)); |
| } |
| else |
| { |
| SuccessOrExit(error = aArgs[0].ParseAsUint32(leaseConfig.mMinLease)); |
| SuccessOrExit(error = aArgs[1].ParseAsUint32(leaseConfig.mMaxLease)); |
| SuccessOrExit(error = aArgs[2].ParseAsUint32(leaseConfig.mMinKeyLease)); |
| SuccessOrExit(error = aArgs[3].ParseAsUint32(leaseConfig.mMaxKeyLease)); |
| VerifyOrExit(aArgs[4].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| error = otSrpServerSetLeaseConfig(GetInstancePtr(), &leaseConfig); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError SrpServer::Process<Cmd("host")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| const otSrpServerHost *host; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| host = nullptr; |
| while ((host = otSrpServerGetNextHost(GetInstancePtr(), host)) != nullptr) |
| { |
| const otIp6Address *addresses; |
| uint8_t addressesNum; |
| bool isDeleted = otSrpServerHostIsDeleted(host); |
| |
| OutputLine("%s", otSrpServerHostGetFullName(host)); |
| OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false"); |
| if (isDeleted) |
| { |
| continue; |
| } |
| |
| OutputSpaces(kIndentSize); |
| OutputFormat("addresses: ["); |
| |
| addresses = otSrpServerHostGetAddresses(host, &addressesNum); |
| |
| for (uint8_t i = 0; i < addressesNum; ++i) |
| { |
| OutputIp6Address(addresses[i]); |
| if (i < addressesNum - 1) |
| { |
| OutputFormat(", "); |
| } |
| } |
| |
| OutputLine("]"); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost) |
| { |
| const otIp6Address *addresses; |
| uint8_t addressesNum; |
| |
| addresses = otSrpServerHostGetAddresses(aHost, &addressesNum); |
| |
| OutputFormat("["); |
| for (uint8_t i = 0; i < addressesNum; ++i) |
| { |
| if (i != 0) |
| { |
| OutputFormat(", "); |
| } |
| |
| OutputIp6Address(addresses[i]); |
| } |
| OutputFormat("]"); |
| } |
| |
| template <> otError SrpServer::Process<Cmd("service")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| const otSrpServerHost *host = nullptr; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| while ((host = otSrpServerGetNextHost(GetInstancePtr(), host)) != nullptr) |
| { |
| const otSrpServerService *service = nullptr; |
| |
| while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) |
| { |
| bool isDeleted = otSrpServerServiceIsDeleted(service); |
| const uint8_t *txtData; |
| uint16_t txtDataLength; |
| bool hasSubType = false; |
| otSrpServerLeaseInfo leaseInfo; |
| |
| OutputLine("%s", otSrpServerServiceGetInstanceName(service)); |
| OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false"); |
| |
| if (isDeleted) |
| { |
| continue; |
| } |
| |
| otSrpServerServiceGetLeaseInfo(service, &leaseInfo); |
| |
| OutputFormat(kIndentSize, "subtypes: "); |
| |
| for (uint16_t index = 0;; index++) |
| { |
| char subLabel[OT_DNS_MAX_LABEL_SIZE]; |
| const char *subTypeName = otSrpServerServiceGetSubTypeServiceNameAt(service, index); |
| |
| if (subTypeName == nullptr) |
| { |
| break; |
| } |
| |
| IgnoreError(otSrpServerParseSubTypeServiceName(subTypeName, subLabel, sizeof(subLabel))); |
| OutputFormat("%s%s", hasSubType ? "," : "", subLabel); |
| hasSubType = true; |
| } |
| |
| OutputLine(hasSubType ? "" : "(null)"); |
| |
| OutputLine(kIndentSize, "port: %u", otSrpServerServiceGetPort(service)); |
| OutputLine(kIndentSize, "priority: %u", otSrpServerServiceGetPriority(service)); |
| OutputLine(kIndentSize, "weight: %u", otSrpServerServiceGetWeight(service)); |
| OutputLine(kIndentSize, "ttl: %lu", ToUlong(otSrpServerServiceGetTtl(service))); |
| OutputLine(kIndentSize, "lease: %lu", ToUlong(leaseInfo.mLease / 1000)); |
| OutputLine(kIndentSize, "key-lease: %lu", ToUlong(leaseInfo.mKeyLease / 1000)); |
| |
| txtData = otSrpServerServiceGetTxtData(service, &txtDataLength); |
| OutputFormat(kIndentSize, "TXT: "); |
| OutputDnsTxtData(txtData, txtDataLength); |
| OutputNewLine(); |
| |
| OutputLine(kIndentSize, "host: %s", otSrpServerHostGetFullName(host)); |
| |
| OutputFormat(kIndentSize, "addresses: "); |
| OutputHostAddresses(host); |
| OutputNewLine(); |
| } |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError SrpServer::Process<Cmd("seqnum")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| if (aArgs[0].IsEmpty()) |
| { |
| OutputLine("%u", otSrpServerGetAnycastModeSequenceNumber(GetInstancePtr())); |
| } |
| else |
| { |
| uint8_t sequenceNumber; |
| |
| SuccessOrExit(error = aArgs[0].ParseAsUint8(sequenceNumber)); |
| error = otSrpServerSetAnycastModeSequenceNumber(GetInstancePtr(), sequenceNumber); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| otError SrpServer::Process(Arg aArgs[]) |
| { |
| #define CmdEntry(aCommandString) \ |
| { \ |
| aCommandString, &SrpServer::Process<Cmd(aCommandString)> \ |
| } |
| |
| static constexpr Command kCommands[] = { |
| CmdEntry("addrmode"), |
| #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE |
| CmdEntry("auto"), |
| #endif |
| CmdEntry("disable"), |
| CmdEntry("domain"), |
| CmdEntry("enable"), |
| CmdEntry("host"), |
| CmdEntry("lease"), |
| CmdEntry("seqnum"), |
| CmdEntry("service"), |
| CmdEntry("state"), |
| CmdEntry("ttl"), |
| }; |
| |
| 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_SRP_SERVER_ENABLE |