[srp-client] adding auto-start feature (#6140)

This commit adds auto-start SRP client feature. Config option
`OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` adds support for
this feature in SRP client allowing auto-start mode to be enabled or
disabled. When enabled, the SRP client will monitor the Thread Network
Data for SRP Server Service entries and automatically start and stop
the client when an SRP server is detected. If multiple SRP servers are
found, a random one will be selected. If the selected SRP server is no
longer detected (not longer present in the Thread Network Data), the
SRP client will be stopped and then it may switch to another SRP
server (if available).

This commit also adds support for the new feature in CLI and adds a
new test `test_srp_auto_start_mode.py` covering the behavior of this
feature.
This commit is contained in:
Abtin Keshavarzian
2021-02-19 10:00:19 -08:00
committed by GitHub
parent c261cf2dff
commit ef259cdd6b
13 changed files with 619 additions and 32 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (73)
#define OPENTHREAD_API_VERSION (74)
/**
* @addtogroup api-instance
+69
View File
@@ -171,6 +171,21 @@ typedef void (*otSrpClientCallback)(otError aError,
const otSrpClientService * aRemovedServices,
void * aContext);
/**
* This function pointer type defines the callback used by SRP client to notify user when it is auto-started or stopped.
*
* This is only used when auto-start feature `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
*
* This callback is invoked when auto-start mode is enabled and the SRP client is either automatically started or
* stopped.
*
* @param[in] aSeverSockAddress A non-NULL pointer indicates SRP sever was started and pointer will give the
* selected server socket address. A NULL pointer indicates SRP sever was stopped.
* @param[in] aContext A pointer to an arbitrary context (provided when callback was registered).
*
*/
typedef void (*otSrpClientAutoStartCallback)(const otSockAddr *aServerSockAddr, void *aContext);
/**
* This function starts the SRP client operation.
*
@@ -245,6 +260,60 @@ const otSockAddr *otSrpClientGetServerAddress(otInstance *aInstance);
*/
void otSrpClientSetCallback(otInstance *aInstance, otSrpClientCallback aCallback, void *aContext);
/**
* This function enables the auto-start mode.
*
* This is only available when auto-start feature `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
*
* Config option `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE` specifies the default auto-start mode (whether
* it is enabled or disabled at the start of OT stack).
*
* When auto-start is enabled, the SRP client will monitor the Thread Network Data for SRP Server Service entries
* and automatically start and stop the client when an SRP server is detected.
*
* If multiple SRP servers are found, a random one will be selected. If the selected SRP server is no longer
* detected (not longer present in the Thread Network Data), the SRP client will be stopped and then it may switch
* to another SRP server (if available).
*
* When the SRP client is explicitly started through a successful call to `otSrpClientStart()`, the given SRP server
* address in `otSrpClientStart()` will continue to be used regardless of the state of auto-start mode and whether the
* same SRP server address is discovered or not in the Thread Network Data. In this case, only an explicit
* `otSrpClientStop()` call will stop the client.
*
* @param[in] aInstance A pointer to the OpenThread instance.
* @param[in] aCallback A callback to notify when client is auto-started/stopped. Can be NULL if not needed.
* @param[in] aContext A context to be passed when invoking @p aCallback.
*
*/
void otSrpClientEnableAutoStartMode(otInstance *aInstance, otSrpClientAutoStartCallback aCallback, void *aContext);
/**
* This function disables the auto-start mode.
*
* This is only available when auto-start feature `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
*
* Disabling the auto-start mode will not stop the client if it is already running but the client stops monitoring
* the Thread Network Data to verify that the selected SRP server is still present in it.
*
* Note that a call to `otSrpClientStop()` will also disable the auto-start mode.
*
* @param[in] aInstance A pointer to the OpenThread instance.
*
*/
void otSrpClientDisableAutoStartMode(otInstance *aInstance);
/**
* This function indicates the current state of auto-start mode (enabled or disabled).
*
* This is only available when auto-start feature `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
*
* @param[in] aInstance A pointer to the OpenThread instance.
*
* @returns TRUE if the auto-start mode is enabled, FALSE otherwise.
*
*/
bool otSrpClientIsAutoStartModeEnabled(otInstance *aInstance);
/**
* This function gets the lease interval used in SRP update requests.
*
+18 -9
View File
@@ -57,16 +57,8 @@ fe80:0:0:0:a8cd:6e23:df3d:4193
Done
> srp server enable
Done
> netdata show
Prefixes:
Routes:
Services:
44970 5d c002 s 8400
Done
```
The SRP Server listening UDP port which is `c002`(`49154`) is included in the Server Data (listed by the `netdata show` command).
### Start SRP Client
Start the SRP Client node:
@@ -100,12 +92,29 @@ Done
Done
> srp client service add my-service _ipps._tcp 12345
Done
srp client start fded:5114:8263:1fe1:68bc:ec03:c1ad:9325 49154
> srp client autostart enable
Done
```
The last command enables the auto-start mode on the client which then monitors the network data to discover available SRP servers within the Thread network and automatically starts the client.
Alternatively, the client can be started manually using the `srp client start`.
The SRP Server listening UDP port (which is `c002`(`49154`) in the example below) can be found from the Server Data (listed by the `netdata show` command).
Make sure the SRP Server address & port are used for the `srp client start` command.
```bash
> netdata show
Prefixes:
Routes:
Services:
44970 5d c002 s 8400
Done
srp client start fded:5114:8263:1fe1:68bc:ec03:c1ad:9325 49154
Done
```
### Verify the service status
Check if the host and service has been successfully registered on the client node:
+42 -1
View File
@@ -5,6 +5,7 @@
Usage : `srp client [command] ...`
- [help](#help)
- [autostart](#autostart)
- [callback](#callback)
- [host](#host)
- [keyleaseinterval](#keyleaseinterval)
@@ -12,6 +13,7 @@ Usage : `srp client [command] ...`
- [server](#server)
- [service](#service)
- [start](#start)
- [state](#state)
- [stop](#stop)
## Command Details
@@ -24,6 +26,7 @@ Print SRP client help menu.
```bash
> srp client help
autostart
callback
help
host
@@ -31,10 +34,36 @@ keyleaseinterval
leaseinterval
service
start
state
stop
Done
```
### autostart
Usage `srp client autostart [enable|disable]`
Enable/Disable auto start mode in SRP client. This command requires `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` feature to be enabled.
Get the current autostart mode.
```bash
> srp client autostart
Disabled
Done
```
Set the autostart mode.
```bash
> srp client autostart enable
Done
> srp client autostart
Enabled
Done
```
### callback
Usage `srp client callback [enable|disable]`
@@ -303,13 +332,25 @@ Done
Usage: `srp client start <serveraddr> <serverport>`
Start the SRP client with a given server IPv6 address and port number
Start the SRP client with a given server IPv6 address and port number.
```bash
> srp client start fd00::d88a:618b:384d:e760 4724
Done
```
### state
Usage: `srp client state`
Indicates the state of SRP client, i.e., whether it is enabled or disabled.
```bash
> srp client state
Enabled
Done
```
### stop
Usage: `srp client stop`
+47
View File
@@ -96,6 +96,39 @@ exit:
return error;
}
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
otError SrpClient::ProcessAutoStart(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgsLength == 0)
{
mInterpreter.OutputEnabledDisabledStatus(otSrpClientIsAutoStartModeEnabled(mInterpreter.mInstance));
ExitNow();
}
VerifyOrExit(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
if (strcmp(aArgs[0], "enable") == 0)
{
otSrpClientEnableAutoStartMode(mInterpreter.mInstance, /* aCallback */ nullptr, /* aContext */ nullptr);
}
else if (strcmp(aArgs[0], "disable") == 0)
{
otSrpClientDisableAutoStartMode(mInterpreter.mInstance);
}
else
{
error = OT_ERROR_INVALID_COMMAND;
}
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
otError SrpClient::ProcessCallback(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
@@ -463,6 +496,20 @@ exit:
return error;
}
otError SrpClient::ProcessState(uint8_t aArgsLength, char *aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
otError error = OT_ERROR_NONE;
VerifyOrExit(aArgsLength == 0, error = OT_ERROR_INVALID_ARGS);
mInterpreter.OutputEnabledDisabledStatus(otSrpClientIsRunning(mInterpreter.mInstance));
exit:
return error;
}
otError SrpClient::ProcessStop(uint8_t aArgsLength, char *aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
+4
View File
@@ -100,6 +100,7 @@ private:
otError (SrpClient::*mHandler)(uint8_t aArgsLength, char *aArgs[]);
};
otError ProcessAutoStart(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[]);
@@ -108,6 +109,7 @@ private:
otError ProcessServer(uint8_t aArgsLength, char *aArgs[]);
otError ProcessService(uint8_t aArgsLength, char *aArgs[]);
otError ProcessStart(uint8_t aArgsLength, char *aArgs[]);
otError ProcessState(uint8_t aArgsLength, char *aArgs[]);
otError ProcessStop(uint8_t aArgsLength, char *aArgs[]);
void OutputHostInfo(uint8_t aIndentSize, const otSrpClientHostInfo &aHostInfo);
@@ -125,6 +127,7 @@ private:
const otSrpClientService * aRemovedServices);
static constexpr Command sCommands[] = {
{"autostart", &SrpClient::ProcessAutoStart},
{"callback", &SrpClient::ProcessCallback},
{"help", &SrpClient::ProcessHelp},
{"host", &SrpClient::ProcessHost},
@@ -133,6 +136,7 @@ private:
{"server", &SrpClient::ProcessServer},
{"service", &SrpClient::ProcessService},
{"start", &SrpClient::ProcessStart},
{"state", &SrpClient::ProcessState},
{"stop", &SrpClient::ProcessStop},
};
+23
View File
@@ -78,6 +78,29 @@ void otSrpClientSetCallback(otInstance *aInstance, otSrpClientCallback aCallback
instance.Get<Srp::Client>().SetCallback(aCallback, aContext);
}
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
void otSrpClientEnableAutoStartMode(otInstance *aInstance, otSrpClientAutoStartCallback aCallback, void *aContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<Srp::Client>().EnableAutoStartMode(aCallback, aContext);
}
void otSrpClientDisableAutoStartMode(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<Srp::Client>().DisableAutoStartMode();
}
bool otSrpClientIsAutoStartModeEnabled(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<Srp::Client>().IsAutoStartModeEnabled();
}
#endif // OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
uint32_t otSrpClientGetLeaseInterval(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
+25
View File
@@ -45,6 +45,31 @@
#define OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
*
* Define to 1 to enable SRP Client auto-start feature and its APIs.
*
* When enabled, the SRP client can be configured to automatically start when it detects the presence of an SRP server
* (by monitoring the Thread Network Data for SRP Server Service entries).
*
*/
#ifndef OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
#define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE
*
* Define the default mode (enabled or disabled) of auto-start mode.
*
* This config is applicable/used only when `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
*
*/
#ifndef OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE
#define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE 0
#endif
/**
* @def OPENTHREAD_CONFIG_SRP_CLIENT_DOMAIN_NAME_API_ENABLE
*
+116 -15
View File
@@ -33,8 +33,10 @@
#include "common/instance.hpp"
#include "common/locator-getters.hpp"
#include "common/logging.hpp"
#include "common/random.hpp"
#include "common/settings.hpp"
#include "common/string.hpp"
#include "thread/network_data_service.hpp"
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
@@ -135,6 +137,10 @@ Client::Client(Instance &aInstance)
, mState(kStateStopped)
, mTxFailureRetryCount(0)
, mShouldRemoveKeyLease(false)
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
, mAutoStartModeEnabled(kAutoStartDefaultMode)
, mAutoStartDidSelectServer(false)
#endif
, mUpdateMessageId(0)
, mRetryWaitInterval(kMinRetryWaitInterval)
, mAcceptedLeaseInterval(0)
@@ -143,6 +149,10 @@ Client::Client(Instance &aInstance)
, mSocket(aInstance)
, mCallback(nullptr)
, mCallbackContext(nullptr)
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
, mAutoStartCallback(nullptr)
, mAutoStartContext(nullptr)
#endif
, mDomainName(kDefaultDomainName)
, mTimer(aInstance, Client::HandleTimer)
{
@@ -164,28 +174,33 @@ Client::Client(Instance &aInstance)
static_assert(kRemoved == 7, "kRemoved value is not correct");
}
otError Client::Start(const Ip6::SockAddr &aServerSockAddr)
otError Client::Start(const Ip6::SockAddr &aServerSockAddr, Requester aRequester)
{
otError error = OT_ERROR_NONE;
otError error;
if (GetState() != kStateStopped)
{
VerifyOrExit(aServerSockAddr == mSocket.GetPeerName(), error = OT_ERROR_BUSY);
ExitNow();
}
VerifyOrExit(GetState() == kStateStopped,
error = (aServerSockAddr == GetServerAddress()) ? OT_ERROR_NONE : OT_ERROR_BUSY);
SuccessOrExit(error = mSocket.Open(Client::HandleUdpReceive, this));
SuccessOrExit(error = mSocket.Connect(aServerSockAddr));
otLogInfoSrp("[client] Starting, server %s", aServerSockAddr.ToString().AsCString());
otLogInfoSrp("[client] %starting, server %s", (aRequester == kRequesterUser) ? "S" : "Auto-s",
aServerSockAddr.ToString().AsCString());
Resume();
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
mAutoStartDidSelectServer = (aRequester == kRequesterAuto);
VerifyOrExit((aRequester == kRequesterAuto) && (mAutoStartCallback != nullptr));
mAutoStartCallback(&aServerSockAddr, mAutoStartContext);
#endif
exit:
return error;
}
void Client::Stop(void)
void Client::Stop(Requester aRequester)
{
// Change the state of host info and services so that they are
// added/removed again once the client is started back. In the
@@ -222,8 +237,18 @@ void Client::Stop(void)
ResetRetryWaitInterval();
SetState(kStateStopped);
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
VerifyOrExit((aRequester == kRequesterAuto) && (mAutoStartCallback != nullptr));
mAutoStartCallback(nullptr, mAutoStartContext);
#endif
exit:
return;
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
if (aRequester == kRequesterUser)
{
DisableAutoStartMode();
}
#endif
}
void Client::SetCallback(Callback aCallback, void *aContext)
@@ -267,14 +292,21 @@ void Client::Pause(void)
void Client::HandleNotifierEvents(Events aEvents)
{
VerifyOrExit(aEvents.Contains(kEventThreadRoleChanged));
if (Get<Mle::Mle>().IsDisabled())
if (aEvents.Contains(kEventThreadRoleChanged))
{
Stop();
ExitNow();
HandleRoleChanged();
}
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
if (aEvents.Contains(kEventThreadNetdataChanged))
{
ProcessAutoStart();
}
#endif
}
void Client::HandleRoleChanged(void)
{
if (Get<Mle::Mle>().IsAttached())
{
VerifyOrExit(GetState() == kStatePaused);
@@ -1428,6 +1460,75 @@ void Client::HandleTimer(void)
}
}
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
void Client::EnableAutoStartMode(AutoStartCallback aCallback, void *aContext)
{
mAutoStartCallback = aCallback;
mAutoStartContext = aContext;
VerifyOrExit(!mAutoStartModeEnabled);
mAutoStartModeEnabled = true;
ProcessAutoStart();
exit:
return;
}
void Client::ProcessAutoStart(void)
{
uint16_t numServers = 0;
NetworkData::Service::SrpServer::Info selectedServer;
NetworkData::Service::SrpServer::Info server;
NetworkData::Service::Manager::Iterator iterator;
VerifyOrExit(mAutoStartModeEnabled);
// If the client is not running we check if there is any SRP sever
// info in Network Data and select one randomly and then start the
// client. If the client is already running with a server that was
// selected by the auto-start feature, we verify that the selected
// server is still present in the Network Data.
VerifyOrExit(!IsRunning() || mAutoStartDidSelectServer);
while (Get<NetworkData::Service::Manager>().GetNextSrpServerInfo(iterator, server) == OT_ERROR_NONE)
{
numServers++;
// Choose a server randomly (with uniform distribution) from
// the list of servers. As we iterate through server entries,
// with probability `1/numServers`, we choose to switch the
// current selected server with the new entry. This approach
// results in a uniform/same probability of selection among
// all server entries.
if ((numServers == 1) || (Random::NonCrypto::GetUint16InRange(0, numServers) == 0))
{
selectedServer = server;
}
if (IsRunning() && mAutoStartDidSelectServer && (GetServerAddress() == server.mSockAddr))
{
ExitNow();
}
}
if (IsRunning())
{
otLogInfoSrp("[client] Server %s is no longer present in net data", GetServerAddress().ToString().AsCString());
Stop(kRequesterAuto);
}
VerifyOrExit(numServers > 0);
IgnoreError(Start(selectedServer.mSockAddr, kRequesterAuto));
exit:
return;
}
#endif // OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
const char *Client::ItemStateToString(ItemState aState)
{
static const char *const kItemStateStrings[] = {
+93 -6
View File
@@ -276,7 +276,7 @@ public:
* @retval OT_ERROR_FAILED Failed to open/connect the client's UDP socket.
*
*/
otError Start(const Ip6::SockAddr &aServerSockAddr);
otError Start(const Ip6::SockAddr &aServerSockAddr) { return Start(aServerSockAddr, kRequesterUser); }
/**
* This method stops the SRP client operation.
@@ -284,8 +284,63 @@ public:
* This method stops any further interactions with the SRP server. Note that it does not remove or clear host info
* and/or list of services. It marks all services to be added/removed again once the client is started again.
*
* If `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` (auto-start feature) is enabled, a call to this method
* also disables the auto-start mode.
*
*/
void Stop(void);
void Stop(void) { Stop(kRequesterUser); }
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
/**
* This function pointer type defines the callback used by SRP client to notify user when it is auto-started or
* stopped.
*
*/
typedef otSrpClientAutoStartCallback AutoStartCallback;
/**
* This method enables the auto-start mode.
*
* Config option `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE` specifies the default auto-start mode
* (whether it is enabled or disabled at the start of OT stack).
*
* When auto-start is enabled, the SRP client will monitor the Thread Network Data for SRP Server Service entries
* and automatically start and stop the client when an SRP server is detected.
*
* If multiple SRP servers are found, a random one will be selected. If the selected SRP server is no longer
* detected (not longer present in the Thread Network Data), the SRP client will be stopped and then it may switch
* to another SRP server (if available).
*
* When the SRP client is explicitly started through a successful call to `Start()`, the given SRP server address
* in `Start()` will continue to be used regardless of the state of auto-start mode and whether the same SRP
* server address is discovered or not in the Thread Network Data. In this case, only an explicit `Stop()` call
* will stop the client.
*
* @param[in] aCallback A callback to notify when client is auto-started/stopped. Can be `nullptr` if not needed.
* @param[in] aContext A context to be passed when invoking @p aCallback.
*
*/
void EnableAutoStartMode(AutoStartCallback aCallback, void *aContext);
/**
* This method disables the auto-start mode.
*
* Disabling the auto-start mode will not stop the client if it is already running but the client stops monitoring
* the Thread Network Data to verify that the selected SRP server is still present in it.
*
* Note that a call to `Stop()` will also disable the auto-start mode.
*
*/
void DisableAutoStartMode(void) { mAutoStartModeEnabled = false; }
/**
* This method indicates the current state of auto-start mode (enabled or disabled).
*
* @returns TRUE if the auto-start mode is enabled, FALSE otherwise.
*
*/
bool IsAutoStartModeEnabled(void) const { return mAutoStartModeEnabled; }
#endif // OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
/**
* This method indicates whether the SRP client is running or not.
@@ -623,6 +678,22 @@ private:
kStateToRetry, // SRP update tx failed, waiting to retry.
};
enum : bool
{
kAutoStartDefaultMode = OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE,
};
// This enumeration type is used by the private `Start()` and
// `Stop()` methods to indicate whether it is being requested by the
// user or by the auto-start feature.
enum Requester
{
kRequesterUser,
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
kRequesterAuto,
#endif
};
struct Info : public Clearable<Info>
{
enum : uint16_t
@@ -636,9 +707,12 @@ private:
Crypto::Ecdsa::P256::KeyPair mKeyPair; // The ECDSA key pair.
};
otError Start(const Ip6::SockAddr &aServerSockAddr, Requester aRequester);
void Stop(Requester aRequester);
void Resume(void);
void Pause(void);
void HandleNotifierEvents(Events aEvents);
void HandleRoleChanged(void);
void UpdateServiceStateToRemove(Service &aService);
State GetState(void) const { return mState; }
void SetState(State aState);
@@ -671,6 +745,9 @@ private:
bool ShouldRenewEarly(const Service &aService) const;
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
void ProcessAutoStart(void);
#endif
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_SRP == 1)
static const char *StateToString(State aState);
@@ -681,11 +758,15 @@ private:
static const char kDefaultDomainName[];
static_assert(kMaxTxFailureRetries < 128, "kMaxTxFailureRetries exceed the range of mTxFailureRetryCount (7-bit)");
static_assert(kMaxTxFailureRetries < 16, "kMaxTxFailureRetries exceed the range of mTxFailureRetryCount (4-bit)");
State mState;
uint8_t mTxFailureRetryCount : 7;
uint8_t mTxFailureRetryCount : 4;
bool mShouldRemoveKeyLease : 1;
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
bool mAutoStartModeEnabled : 1;
bool mAutoStartDidSelectServer : 1;
#endif
uint16_t mUpdateMessageId;
uint32_t mRetryWaitInterval;
@@ -697,8 +778,14 @@ private:
Ip6::Udp::Socket mSocket;
Callback mCallback;
void * mCallbackContext;
Callback mCallback;
void * mCallbackContext;
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
AutoStartCallback mAutoStartCallback;
void * mAutoStartContext;
#endif
const char * mDomainName;
HostInfo mHostInfo;
LinkedList<Service> mServices;
+2
View File
@@ -172,6 +172,7 @@ EXTRA_DIST = \
test_route_table.py \
test_router_reattach.py \
test_service.py \
test_srp_auto_start_mode.py \
test_srp_lease.py \
test_srp_name_conflicts.py \
test_srp_register_single_service.py \
@@ -225,6 +226,7 @@ check_SCRIPTS = \
test_route_table.py \
test_router_reattach.py \
test_service.py \
test_srp_auto_start_mode.py \
test_srp_lease.py \
test_srp_name_conflicts.py \
test_srp_register_single_service.py \
+28
View File
@@ -928,6 +928,34 @@ class NodeImpl:
self.send_command(f'srp client stop')
self._expect_done()
def srp_client_get_state(self):
cmd = 'srp client state'
self.send_command(cmd)
return self._expect_command_output(cmd)[0]
def srp_client_get_auto_start_mode(self):
cmd = 'srp client autostart'
self.send_command(cmd)
return self._expect_command_output(cmd)[0]
def srp_client_enable_auto_start_mode(self):
self.send_command(f'srp client autostart enable')
self._expect_done()
def srp_client_disable_auto_start_mode(self):
self.send_command(f'srp client autostart able')
self._expect_done()
def srp_client_get_server_address(self):
cmd = 'srp client server address'
self.send_command(cmd)
return self._expect_command_output(cmd)[0]
def srp_client_get_server_port(self):
cmd = 'srp client server port'
self.send_command(cmd)
return int(self._expect_command_output(cmd)[0])
def srp_client_get_host_state(self):
cmd = 'srp client host state'
self.send_command(cmd)
+151
View File
@@ -0,0 +1,151 @@
#!/usr/bin/env python3
#
# Copyright (c) 2021, 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.
#
import ipaddress
import unittest
import command
import thread_cert
# Test description:
# This test verifies SRP client auto-start functionality that SRP client can
# correctly discover and connect to SRP server.
#
# Topology:
#
# CLIENT (leader) -- SERVER1 (router)
# |
# |
# SERVER2 (router)
#
CLIENT = 1
SERVER1 = 2
SERVER2 = 3
class SrpAutoStartMode(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
CLIENT: {
'name': 'SRP_CLIENT',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rdn',
'panid': 0xface
},
SERVER1: {
'name': 'SRP_SERVER1',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rdn',
'panid': 0xface,
'router_selection_jitter': 1
},
SERVER2: {
'name': 'SRP_SERVER2',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rdn',
'panid': 0xface,
'router_selection_jitter': 1
},
}
def test(self):
client = self.nodes[CLIENT]
server1 = self.nodes[SERVER1]
server2 = self.nodes[SERVER2]
#
# 0. Start the server & client devices.
#
client.srp_server_set_enabled(False)
client.start()
self.simulator.go(5)
self.assertEqual(client.get_state(), 'leader')
server1.srp_server_set_enabled(True)
server2.srp_server_set_enabled(False)
server1.start()
server2.start()
self.simulator.go(5)
self.assertEqual(server1.get_state(), 'router')
self.assertEqual(server2.get_state(), 'router')
#
# 1. Enable auto start mode on client and check that server1 is used.
#
self.assertEqual(client.srp_client_get_state(), 'Disabled')
client.srp_client_enable_auto_start_mode()
self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled')
self.simulator.go(2)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
self.assertEqual(client.srp_client_get_server_port(), client.get_srp_server_port())
#
# 2. Disable server1 and check client is stopped/disabled.
#
server1.srp_server_set_enabled(False)
self.simulator.go(5)
self.assertEqual(client.srp_client_get_state(), 'Disabled')
#
# 3. Enable server2 and check client starts again.
#
server2.srp_server_set_enabled(True)
self.simulator.go(5)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
prev_port = client.srp_client_get_server_port()
#
# 4. Enable both servers and check client stays with server2.
#
server1.srp_server_set_enabled(True)
self.simulator.go(2)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
self.assertEqual(client.srp_client_get_server_port(), prev_port)
#
# 5. Disable server2 and check client switches to server1.
#
server2.srp_server_set_enabled(False)
self.simulator.go(5)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
self.assertNotEqual(client.srp_client_get_server_port(), prev_port)
if __name__ == '__main__':
unittest.main()