mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 23:57:47 +00:00
[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:
committed by
Jonathan Hui
parent
966baf5e6b
commit
f3e987baa9
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
Reference in New Issue
Block a user