[cli] add CLI support for SRP client (#6038)

This commit adds CLI support under `srp client` for SRP Client.
It also adds `README_SRP_CLIENT.md` to document the newly added
CLI commands.
This commit is contained in:
Abtin Keshavarzian
2021-01-22 13:19:21 -08:00
committed by Jonathan Hui
parent 966baf5e6b
commit f3e987baa9
11 changed files with 1006 additions and 0 deletions
+1
View File
@@ -420,6 +420,7 @@ LOCAL_SRC_FILES := \
src/cli/cli_dataset.cpp \
src/cli/cli_joiner.cpp \
src/cli/cli_network_data.cpp \
src/cli/cli_srp_client.cpp \
src/cli/cli_uart.cpp \
src/cli/cli_udp.cpp \
$(NULL)
+2
View File
@@ -45,6 +45,8 @@ openthread_cli_sources = [
"cli_joiner.hpp",
"cli_network_data.cpp",
"cli_network_data.hpp",
"cli_srp_client.cpp",
"cli_srp_client.hpp",
"cli_uart.cpp",
"cli_uart.hpp",
"cli_udp.cpp",
+1
View File
@@ -47,6 +47,7 @@ set(COMMON_SOURCES
cli_dataset.cpp
cli_joiner.cpp
cli_network_data.cpp
cli_srp_client.cpp
cli_uart.cpp
cli_udp.cpp
)
+2
View File
@@ -158,6 +158,7 @@ SOURCES_COMMON = \
cli_dataset.cpp \
cli_joiner.cpp \
cli_network_data.cpp \
cli_srp_client.cpp \
cli_uart.cpp \
cli_udp.cpp \
$(NULL)
@@ -180,6 +181,7 @@ noinst_HEADERS = \
cli_dataset.hpp \
cli_joiner.hpp \
cli_network_data.hpp \
cli_srp_client.hpp \
cli_uart.hpp \
cli_udp.hpp \
x509_cert_key.hpp \
+1
View File
@@ -100,6 +100,7 @@ Done
- [singleton](#singleton)
- [sntp](#sntp-query-sntp-server-ip-sntp-server-port)
- [state](#state)
- [srp](README_SRP.md)
- [thread](#thread-start)
- [txpower](#txpower)
- [unsecureport](#unsecureport-add-port)
+289
View File
@@ -0,0 +1,289 @@
# OpenThread CLI - SRP Client
## Command List
Usage : `srp client [command] ...`
- [help](#help)
- [callback](#callback)
- [host](#host)
- [keyleaseinterval](#keyleaseinterval)
- [leaseinterval](#leaseinterval)
- [service](#service)
- [start](#start)
- [stop](#stop)
## Command Details
### help
Usage: `srp client help`
Print SRP client help menu.
```bash
> srp client help
callback
help
host
keyleaseinterval
leaseinterval
service
start
stop
Done
```
### callback
Usage `srp client callback [enable|disable]`
Enable/Disable printing callback events from SRP client.
Get current callback mode
```bash
> srp client callback
Disabled
Done
```
Set callback mode
```bash
> srp client callback enable
Done
> srp client callback
Enabled
Done
```
#### Example
When two services are successfully registered:
```bash
SRP client callback - error:OK
Host info:
name:"dev4312", state:Registered, addrs:[fd00:0:0:0:0:0:0:1]
Service list:
instance:"ins2", name:"_test2._udp", state:Registered, port:111, priority:1, weight:1
instance:"ins1", name:"_test1._udp", state:Registered, port:777, priority:0, weight:0
```
When service `ins2` is removed:
```bash
SRP client callback - error:OK
Host info:
name:"dev4312", state:Registered, addrs:[fd00:0:0:0:0:0:0:1]
Service list:
instance:"ins1", name:"_test1._udp", state:Registered, port:777, priority:0, weight:0
Removed service list:
instance:"ins2", name:"_test2._udp", state:Removed, port:111, priority:1, weight:1
```
When host info (and all services) is removed:
```bash
SRP client callback - error:OK
Host info:
name:"dev4312", state:Removed, addrs:[fd00:0:0:0:0:0:0:1]
Service list:
Removed service list:
instance:"ins1", name:"_test1._udp", state:Removed, port:777, priority:0, weight:0
```
### host
Usage: `srp client host`
Print the full host info (host name, state, list of host addresses).
```bash
> srp client host
name:"dev4312", state:Registered, addrs:[fd00:0:0:0:0:0:0:1234, fd00:0:0:0:0:0:0:beef]
Done
```
### host name
Usage: `srp client host name [name]`
Get the host name.
```bash
> srp client host name
dev4312
Done
```
Set host name (can be set when the host is removed or not yet registered with server).
```bash
srp client host name dev4312
Done
```
### host address
Usage : `srp client host address [<address> ...]`
Get the list of host addresses.
```bash
> srp client host address
fd00:0:0:0:0:0:0:1234
fd00:0:0:0:0:0:0:beef
Done
```
Set the list of host addresses (can be set while client is running to update the host addresses)
```bash
> srp client host address fd00::cafe
Done
```
### host state
Usage: `srp client host state`
Get the host state.
```bash
> srp client host state
Registered
Done
```
The possible states are (same value for service state):
- `ToAdd`: item to be added/registered.
- `Adding`: item is being added/registered.
- `ToRefresh`: item to be refreshed (renew lease).
- `Refreshing`: item is being refreshed.
- `ToRemove`: item to be removed.
- `Removing`: item is being removed.
- `Registered`: item is registered with server.
- `Removed`: item is removed.
### host remove
Usage: `srp client host remove [removekeylease]`
Remove host info and all services from server. `removekeylease` is boolean value indicating whether or not the host key lease should also be removed
```bash
> srp client host remove 1
Done
```
### host clear
Usage: `srp client host clear`
Clear host info and all services on client (unlike `host remove`, with `host clear` no update is sent to server).
```bash
> srp client host clear
Done
```
### keyleaseinterval
Usage: `srp client keyleaseinterval [interval]`
Get the key lease interval (in seconds).
```bash
> srp client keyleaseinterval
1209600
Done
>
```
Set the key lease interval.
```bash
> srp client keyleaseinterval 864000
Done
```
### leaseinterval
Usage: `srp client leaseinterval [interval]`
Get the lease interval (in seconds).
```bash
> srp client leaseinterval
7200
Done
>
```
Set the lease interval.
```bash
> srp client leaseinterval 3600
Done
```
### service
Usage: `srp client service`
Print the list of services.
```bash
> srp client service
instance:"ins2", name:"_test2._udp", state:Registered, port:111, priority:1, weight:1
instance:"ins1", name:"_test1._udp", state:Registered, port:777, priority:0, weight:0
Done
```
### service add
Usage: `srp client service add <instancename> <servicename> <port> [priority] [weight] [txt]`
Add a service with a given instance name, service name, port number, priority, weight and txt values. The priority and weight are optional and if not provided zero will be used. The txt should follow hex-string format and is treated as an already encoded TXT data byte sequence. It is also optional and if not provided it is considered empty.
```bash
> srp client service add ins2 _test2._udp 111 1 1
Done
```
### service remove
Usage: `srp client service remove <instancename> <servicename>`
Remove a service with a give instance name and service name.
```bash
> srp client service remove ins2 _test2._udp
Done
```
### start
Usage: `srp client start <serveraddr> <serverport>`
Start the SRP client with a given server IPv6 address and port number
```bash
> srp client start fd00::d88a:618b:384d:e760 4724
Done
```
### stop
Usage: `srp client stop`
Stop the SRP client.
```bash
> srp client stop
Done
```
+27
View File
@@ -140,6 +140,9 @@ Interpreter::Interpreter(Instance *aInstance)
#endif
#if OPENTHREAD_CONFIG_JOINER_ENABLE
, mJoiner(*this)
#endif
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
, mSrpClient(*this)
#endif
, mInstance(aInstance)
{
@@ -3869,6 +3872,30 @@ void Interpreter::HandleSntpResponse(uint64_t aTime, otError aResult)
}
#endif // OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
otError Interpreter::ProcessSrp(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgsLength == 0)
{
OutputLine("client");
// OutputLine("server");
ExitNow();
}
if (strcmp(aArgs[0], "client") == 0)
{
ExitNow(error = mSrpClient.Process(aArgsLength - 1, aArgs + 1));
}
error = OT_ERROR_INVALID_COMMAND;
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
otError Interpreter::ProcessState(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
+12
View File
@@ -50,6 +50,7 @@
#include "cli/cli_dataset.hpp"
#include "cli/cli_joiner.hpp"
#include "cli/cli_network_data.hpp"
#include "cli/cli_srp_client.hpp"
#include "cli/cli_udp.hpp"
#if OPENTHREAD_CONFIG_COAP_API_ENABLE
#include "cli/cli_coap.hpp"
@@ -86,6 +87,7 @@ class Interpreter
friend class Dataset;
friend class Joiner;
friend class NetworkData;
friend class SrpClient;
friend class UdpExample;
public:
@@ -493,6 +495,9 @@ private:
otError ProcessSingleton(uint8_t aArgsLength, char *aArgs[]);
#if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
otError ProcessSntp(uint8_t aArgsLength, char *aArgs[]);
#endif
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
otError ProcessSrp(uint8_t aArgsLength, char *aArgs[]);
#endif
otError ProcessState(uint8_t aArgsLength, char *aArgs[]);
otError ProcessThread(uint8_t aArgsLength, char *aArgs[]);
@@ -754,6 +759,9 @@ private:
{"singleton", &Interpreter::ProcessSingleton},
#if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
{"sntp", &Interpreter::ProcessSntp},
#endif
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
{"srp", &Interpreter::ProcessSrp},
#endif
{"state", &Interpreter::ProcessState},
{"thread", &Interpreter::ProcessThread},
@@ -806,6 +814,10 @@ private:
Joiner mJoiner;
#endif
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
SrpClient mSrpClient;
#endif
Instance *mInstance;
};
+24
View File
@@ -99,4 +99,28 @@
#error "Unsupported CLI transport!"
#endif
/**
* @def OPENTHREAD_CONFIG_CLI_SRP_CLIENT_MAX_SERVICES
*
* The maximum number of service entries supported by SRP client.
*
* This is only applicable when SRP client is enabled, i.e. OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE is set.
*
*/
#ifndef OPENTHREAD_CONFIG_CLI_SRP_CLIENT_MAX_SERVICES
#define OPENTHREAD_CONFIG_CLI_SRP_CLIENT_MAX_SERVICES 2
#endif
/**
* @def OPENTHREAD_CONFIG_CLI_SRP_CLIENT_MAX_HOST_ADDRESSES
*
* The maximum number of host IPv6 address entries supported by SRP client.
*
* This is only applicable when SRP client is enabled, i.e. OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE is set.
*
*/
#ifndef OPENTHREAD_CONFIG_CLI_SRP_CLIENT_MAX_HOST_ADDRESSES
#define OPENTHREAD_CONFIG_CLI_SRP_CLIENT_MAX_HOST_ADDRESSES 2
#endif
#endif // CONFIG_CLI_H_
+496
View File
@@ -0,0 +1,496 @@
/*
* 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 Client.
*/
#include "cli_srp_client.hpp"
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
#include <string.h>
#include "cli/cli.hpp"
#include "utils/parse_cmdline.hpp"
using ot::Utils::CmdLineParser::ParseAsBool;
using ot::Utils::CmdLineParser::ParseAsHexString;
using ot::Utils::CmdLineParser::ParseAsIp6Address;
using ot::Utils::CmdLineParser::ParseAsUint16;
using ot::Utils::CmdLineParser::ParseAsUint32;
namespace ot {
namespace Cli {
constexpr SrpClient::Command SrpClient::sCommands[];
template <uint16_t kDestSize> static otError CopyString(char (&aDestination)[kDestSize], const char *aSource)
{
// Copies a string from `aSource` to `aDestination` (char array),
// verifying that the string fits in the destination array.
otError error = OT_ERROR_NONE;
size_t len = strlen(aSource);
VerifyOrExit(len + 1 <= kDestSize, error = OT_ERROR_INVALID_ARGS);
memcpy(aDestination, aSource, len + 1);
exit:
return error;
}
SrpClient::SrpClient(Interpreter &aInterpreter)
: mInterpreter(aInterpreter)
, mCallbackEnabled(false)
{
for (Service &service : mServicePool)
{
service.MarkAsNotInUse();
}
memset(mHostAddresses, 0, sizeof(mHostAddresses));
}
otError SrpClient::Process(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_INVALID_COMMAND;
const Command *command;
VerifyOrExit(aArgsLength != 0, IgnoreError(ProcessHelp(0, nullptr)));
command = Utils::LookupTable::Find(aArgs[0], sCommands);
VerifyOrExit(command != nullptr);
error = (this->*command->mHandler)(aArgsLength - 1, aArgs + 1);
exit:
return error;
}
otError SrpClient::ProcessCallback(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgsLength == 0)
{
mInterpreter.OutputLine(mCallbackEnabled ? "Enabled" : "Disabled");
ExitNow();
}
VerifyOrExit(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
if (strcmp(aArgs[0], "enable") == 0)
{
mCallbackEnabled = true;
}
else if (strcmp(aArgs[0], "disable") == 0)
{
mCallbackEnabled = false;
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
exit:
return error;
}
otError SrpClient::ProcessHelp(uint8_t aArgsLength, char *aArgs[])
{
OT_UNUSED_VARIABLE(aArgsLength);
OT_UNUSED_VARIABLE(aArgs);
for (const Command &command : sCommands)
{
mInterpreter.OutputLine(command.mName);
}
return OT_ERROR_NONE;
}
otError SrpClient::ProcessHost(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgsLength == 0)
{
OutputHostInfo(0, *otSrpClientGetHostInfo(mInterpreter.mInstance));
ExitNow();
}
if (strcmp(aArgs[0], "name") == 0)
{
if (aArgsLength == 1)
{
const char *name = otSrpClientGetHostInfo(mInterpreter.mInstance)->mName;
mInterpreter.OutputLine("%s", (name != nullptr) ? name : "(null)");
}
else
{
VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = CopyString(mHostName, aArgs[1]));
error = otSrpClientSetHostName(mInterpreter.mInstance, mHostName);
}
}
else if (strcmp(aArgs[0], "state") == 0)
{
VerifyOrExit(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
mInterpreter.OutputLine("%s",
otSrpClientItemStateToString(otSrpClientGetHostInfo(mInterpreter.mInstance)->mState));
}
else if (strcmp(aArgs[0], "address") == 0)
{
if (aArgsLength == 1)
{
const otSrpClientHostInfo *hostInfo = otSrpClientGetHostInfo(mInterpreter.mInstance);
for (uint8_t index = 0; index < hostInfo->mNumAddresses; index++)
{
mInterpreter.OutputIp6Address(hostInfo->mAddresses[index]);
mInterpreter.OutputLine("");
}
}
else
{
uint8_t numAddresses;
otIp6Address addresses[kMaxHostAddresses];
numAddresses = 0;
memset(addresses, 0, sizeof(addresses));
while (aArgsLength > 1)
{
VerifyOrExit(numAddresses < kMaxHostAddresses, error = OT_ERROR_NO_BUFS);
aArgsLength--;
aArgs++;
SuccessOrExit(error = ParseAsIp6Address(aArgs[0], addresses[numAddresses++]));
}
VerifyOrExit(numAddresses > 0, error = OT_ERROR_INVALID_ARGS);
memcpy(mHostAddresses, addresses, sizeof(addresses));
error = otSrpClientSetHostAddresses(mInterpreter.mInstance, mHostAddresses, numAddresses);
}
}
else if (strcmp(aArgs[0], "remove") == 0)
{
bool removeKeyLease = false;
if (aArgsLength > 1)
{
VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = ParseAsBool(aArgs[1], removeKeyLease));
}
error = otSrpClientRemoveHostAndServices(mInterpreter.mInstance, removeKeyLease);
}
else if (strcmp(aArgs[0], "clear") == 0)
{
VerifyOrExit(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
otSrpClientClearHostAndServices(mInterpreter.mInstance);
for (Service &poolEntry : mServicePool)
{
poolEntry.MarkAsNotInUse();
}
}
else
{
error = OT_ERROR_INVALID_COMMAND;
}
exit:
return error;
}
otError SrpClient::ProcessLeaseInterval(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
uint32_t interval;
if (aArgsLength == 0)
{
mInterpreter.OutputLine("%u", otSrpClientGetLeaseInterval(mInterpreter.mInstance));
ExitNow();
}
VerifyOrExit(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = ParseAsUint32(aArgs[0], interval));
otSrpClientSetLeaseInterval(mInterpreter.mInstance, interval);
exit:
return error;
}
otError SrpClient::ProcessKeyLeaseInterval(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
uint32_t interval;
if (aArgsLength == 0)
{
mInterpreter.OutputLine("%u", otSrpClientGetKeyLeaseInterval(mInterpreter.mInstance));
ExitNow();
}
VerifyOrExit(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = ParseAsUint32(aArgs[0], interval));
otSrpClientSetKeyLeaseInterval(mInterpreter.mInstance, interval);
exit:
return error;
}
otError SrpClient::ProcessService(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgsLength == 0)
{
OutputServiceList(0, otSrpClientGetServices(mInterpreter.mInstance));
ExitNow();
}
if (strcmp(aArgs[0], "add") == 0)
{
// `add` <instance-name> <service-name> <port> [priority] [weight] [txt]
Service *entry = nullptr;
VerifyOrExit(4 <= aArgsLength && aArgsLength <= 7, error = OT_ERROR_INVALID_ARGS);
for (Service &poolEntry : mServicePool)
{
if (!poolEntry.IsInUse())
{
entry = &poolEntry;
break;
}
}
VerifyOrExit(entry != nullptr, error = OT_ERROR_NO_BUFS);
memset(&entry->mService, 0, sizeof(entry->mService));
SuccessOrExit(error = CopyString(entry->mInstanceName, aArgs[1]));
entry->mService.mInstanceName = entry->mInstanceName;
SuccessOrExit(error = CopyString(entry->mServiceName, aArgs[2]));
entry->mService.mName = entry->mServiceName;
SuccessOrExit(error = ParseAsUint16(aArgs[3], entry->mService.mPort));
if (aArgsLength >= 5)
{
SuccessOrExit(error = ParseAsUint16(aArgs[4], entry->mService.mPriority));
}
if (aArgsLength >= 6)
{
SuccessOrExit(error = ParseAsUint16(aArgs[5], entry->mService.mWeight));
}
if (aArgsLength >= 7)
{
entry->mService.mNumTxtEntries = 1;
entry->mService.mTxtEntries = &entry->mTxtEntry;
entry->mTxtEntry.mKey = nullptr; // Treat`mValue` as an already encoded TXT-DATA
entry->mTxtEntry.mValue = entry->mTxtBuffer;
entry->mTxtEntry.mValueLength = sizeof(entry->mTxtBuffer);
SuccessOrExit(error = ParseAsHexString(aArgs[6], entry->mTxtEntry.mValueLength, entry->mTxtBuffer));
}
error = otSrpClientAddService(mInterpreter.mInstance, &entry->mService);
if (error != OT_ERROR_NONE)
{
entry->MarkAsNotInUse();
}
}
else if (strcmp(aArgs[0], "remove") == 0)
{
// `remove` <instance-name> <service-name>
Service *entry = nullptr;
VerifyOrExit(aArgsLength == 3, error = OT_ERROR_INVALID_ARGS);
for (Service &poolEntry : mServicePool)
{
if (poolEntry.IsInUse() && (strcmp(aArgs[1], poolEntry.mInstanceName) == 0) &&
(strcmp(aArgs[2], poolEntry.mServiceName) == 0))
{
entry = &poolEntry;
break;
}
}
VerifyOrExit(entry != nullptr, error = OT_ERROR_NOT_FOUND);
error = otSrpClientRemoveService(mInterpreter.mInstance, &entry->mService);
}
else
{
error = OT_ERROR_INVALID_COMMAND;
}
exit:
return error;
}
void SrpClient::OutputHostInfo(uint8_t aIndentSize, const otSrpClientHostInfo &aHostInfo)
{
mInterpreter.OutputFormat(aIndentSize, "name:");
if (aHostInfo.mName != nullptr)
{
mInterpreter.OutputFormat("\"%s\"", aHostInfo.mName);
}
else
{
mInterpreter.OutputFormat("(null)");
}
mInterpreter.OutputFormat(", state:%s, addrs:[", otSrpClientItemStateToString(aHostInfo.mState));
for (uint8_t index = 0; index < aHostInfo.mNumAddresses; index++)
{
if (index > 0)
{
mInterpreter.OutputFormat(", ");
}
mInterpreter.OutputIp6Address(aHostInfo.mAddresses[index]);
}
mInterpreter.OutputLine("]");
}
void SrpClient::OutputServiceList(uint8_t aIndentSize, const otSrpClientService *aServices)
{
while (aServices != nullptr)
{
OutputService(aIndentSize, *aServices);
aServices = aServices->mNext;
}
}
void SrpClient::OutputService(uint8_t aIndentSize, const otSrpClientService &aService)
{
mInterpreter.OutputLine(aIndentSize, "instance:\"%s\", name:\"%s\", state:%s, port:%d, priority:%d, weight:%d",
aService.mInstanceName, aService.mName, otSrpClientItemStateToString(aService.mState),
aService.mPort, aService.mPriority, aService.mWeight);
}
otError SrpClient::ProcessStart(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
otSockAddr serverSockAddr;
VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = ParseAsIp6Address(aArgs[0], serverSockAddr.mAddress));
SuccessOrExit(error = ParseAsUint16(aArgs[1], serverSockAddr.mPort));
error = otSrpClientStart(mInterpreter.mInstance, &serverSockAddr, SrpClient::HandleCallback, this);
exit:
return error;
}
otError SrpClient::ProcessStop(uint8_t aArgsLength, char *aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
otError error = OT_ERROR_NONE;
VerifyOrExit(aArgsLength == 0, error = OT_ERROR_INVALID_ARGS);
otSrpClientStop(mInterpreter.mInstance);
exit:
return error;
}
void SrpClient::HandleCallback(otError aError,
const otSrpClientHostInfo *aHostInfo,
const otSrpClientService * aServices,
const otSrpClientService * aRemovedServices,
void * aContext)
{
static_cast<SrpClient *>(aContext)->HandleCallback(aError, aHostInfo, aServices, aRemovedServices);
}
void SrpClient::HandleCallback(otError aError,
const otSrpClientHostInfo *aHostInfo,
const otSrpClientService * aServices,
const otSrpClientService * aRemovedServices)
{
otSrpClientService *next;
if (mCallbackEnabled)
{
mInterpreter.OutputLine("SRP client callback - error:%s", otThreadErrorToString(aError));
mInterpreter.OutputLine("Host info:");
OutputHostInfo(kIndentSize, *aHostInfo);
mInterpreter.OutputLine("Service list:");
OutputServiceList(kIndentSize, aServices);
if (aRemovedServices != nullptr)
{
mInterpreter.OutputLine("Removed service list:");
OutputServiceList(kIndentSize, aRemovedServices);
}
}
// Go through removed services and mark the corresponding entry in
// `mServicePool` as "not in use".
for (const otSrpClientService *service = aRemovedServices; service != nullptr; service = next)
{
next = service->mNext;
for (Service &poolEntry : mServicePool)
{
if (service == &poolEntry.mService)
{
poolEntry.MarkAsNotInUse();
break;
}
}
}
}
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
+151
View File
@@ -0,0 +1,151 @@
/*
* 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 contains definitions for a simple CLI to control SRP Client.
*/
#ifndef CLI_SRP_CLIENT_HPP_
#define CLI_SRP_CLIENT_HPP_
#include "openthread-core-config.h"
#include <openthread/srp_client.h>
#include "cli/cli_config.h"
#include "utils/lookup_table.hpp"
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
namespace ot {
namespace Cli {
class Interpreter;
/**
* This class implements the SRP Client CLI interpreter.
*
*/
class SrpClient
{
public:
/**
* Constructor
*
* @param[in] aInterpreter The CLI interpreter.
*
*/
explicit SrpClient(Interpreter &aInterpreter);
/**
* This method interprets a list of CLI arguments.
*
* @param[in] aArgsLength The number of elements in @p aArgs.
* @param[in] aArgs A pointer to an array of command line arguments.
*
*/
otError Process(uint8_t aArgsLength, char *aArgs[]);
private:
enum : uint8_t
{
kMaxServices = OPENTHREAD_CONFIG_CLI_SRP_CLIENT_MAX_SERVICES,
kMaxHostAddresses = OPENTHREAD_CONFIG_CLI_SRP_CLIENT_MAX_HOST_ADDRESSES,
kNameSize = 64,
kTxtSize = 255,
kIndentSize = 4,
};
struct Service
{
void MarkAsNotInUse(void) { mService.mNext = &mService; }
bool IsInUse(void) const { return (mService.mNext != &mService); }
otSrpClientService mService;
otSrpTxtEntry mTxtEntry;
char mInstanceName[kNameSize];
char mServiceName[kNameSize];
uint8_t mTxtBuffer[kTxtSize];
};
struct Command
{
const char *mName;
otError (SrpClient::*mHandler)(uint8_t aArgsLength, char *aArgs[]);
};
otError ProcessCallback(uint8_t aArgsLength, char *aArgs[]);
otError ProcessHelp(uint8_t aArgsLength, char *aArgs[]);
otError ProcessHost(uint8_t aArgsLength, char *aArgs[]);
otError ProcessLeaseInterval(uint8_t aArgsLength, char *aArgs[]);
otError ProcessKeyLeaseInterval(uint8_t aArgsLength, char *aArgs[]);
otError ProcessService(uint8_t aArgsLength, char *aArgs[]);
otError ProcessStart(uint8_t aArgsLength, char *aArgs[]);
otError ProcessStop(uint8_t aArgsLength, char *aArgs[]);
void OutputHostInfo(uint8_t aIndentSize, const otSrpClientHostInfo &aHostInfo);
void OutputServiceList(uint8_t aIndentSize, const otSrpClientService *aServices);
void OutputService(uint8_t aIndentSize, const otSrpClientService &aService);
static void HandleCallback(otError aError,
const otSrpClientHostInfo *aHostInfo,
const otSrpClientService * aServices,
const otSrpClientService * aRemovedServices,
void * aContext);
void HandleCallback(otError aError,
const otSrpClientHostInfo *aHostInfo,
const otSrpClientService * aServices,
const otSrpClientService * aRemovedServices);
static constexpr Command sCommands[] = {
{"callback", &SrpClient::ProcessCallback},
{"help", &SrpClient::ProcessHelp},
{"host", &SrpClient::ProcessHost},
{"keyleaseinterval", &SrpClient::ProcessKeyLeaseInterval},
{"leaseinterval", &SrpClient::ProcessLeaseInterval},
{"service", &SrpClient::ProcessService},
{"start", &SrpClient::ProcessStart},
{"stop", &SrpClient::ProcessStop},
};
static_assert(Utils::LookupTable::IsSorted(sCommands), "Command Table is not sorted");
Interpreter &mInterpreter;
bool mCallbackEnabled;
char mHostName[kNameSize];
otIp6Address mHostAddresses[kMaxHostAddresses];
Service mServicePool[kMaxServices];
};
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
#endif // CLI_SRP_CLIENT_HPP_