mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 11:47:46 +00:00
[srp-client] new feature to allow lease and key lease per service (#8211)
This commit add a new feature in `Srp::Client` to allow user to specify the lease and/or key lease intervals explicitly per service. The lease intervals in a service can be left unspecified(set to zero) in which case the default lease intervals will be used. In an SRP Update message, the lease info is included in additional section in an Update Lease Option record. Therefore the lease values are applicable to the entire message and all its records. If we have services with different lease intervals, they need to be registered in separate messages. This commit updates `Srp::Client` to implement such a mechanism. When preparing an SRP message, we first determine the lease and key lease intervals and ensure the services using matching intervals are included in the message. This commit also updates and simplifies the "single service mode" functionality to use the newly added mechanism for tracking which services are included in the message. This commit adds `test_srp_register_services_diff_lease` which covers the behavior of the newly added mechanisms.
This commit is contained in:
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (248)
|
||||
#define OPENTHREAD_API_VERSION (249)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -88,28 +88,34 @@ typedef struct otSrpClientHostInfo
|
||||
* and stay constant after an instance of this structure is passed to OpenThread from `otSrpClientAddService()` or
|
||||
* `otSrpClientRemoveService()`.
|
||||
*
|
||||
* The `mState`, `mData`, `mNext` fields are used/managed by OT core only. Their value is ignored when an instance of
|
||||
* `otSrpClientService` is passed in `otSrpClientAddService()` or `otSrpClientRemoveService()` or other functions. The
|
||||
* caller does not need to set these fields.
|
||||
*
|
||||
* The `mLease` and `mKeyLease` fields specify the desired lease and key lease intervals for this service. Zero value
|
||||
* indicates that the interval is unspecified and then the default lease or key lease intervals from
|
||||
* `otSrpClientGetLeaseInterval()` and `otSrpClientGetKeyLeaseInterval()` are used for this service. If the key lease
|
||||
* interval (whether set explicitly or determined from the default) is shorter than the lease interval for a service,
|
||||
* SRP client will re-use the lease interval value for key lease interval as well. For example, if in service `mLease`
|
||||
* is explicitly set to 2 days and `mKeyLease` is set to zero and default key lease is set to 1 day, then when
|
||||
* registering this service, the requested key lease for this service is also set to 2 days.
|
||||
*
|
||||
*/
|
||||
typedef struct otSrpClientService
|
||||
{
|
||||
const char * mName; ///< The service name labels (e.g., "_chip._udp", not the full domain name).
|
||||
const char * mInstanceName; ///< The service instance name label (not the full name).
|
||||
const char *const * mSubTypeLabels; ///< Array of service sub-type labels (must end with `NULL` or can be `NULL`).
|
||||
const otDnsTxtEntry *mTxtEntries; ///< Array of TXT entries (number of entries is given by `mNumTxtEntries`).
|
||||
uint16_t mPort; ///< The service port number.
|
||||
uint16_t mPriority; ///< The service priority.
|
||||
uint16_t mWeight; ///< The service weight.
|
||||
uint8_t mNumTxtEntries; ///< Number of entries in the `mTxtEntries` array.
|
||||
|
||||
/**
|
||||
* @note The following fields are used/managed by OT core only. Their values do not matter and are ignored when an
|
||||
* instance of `otSrpClientService` is passed in `otSrpClientAddService()` or `otSrpClientRemoveService()`. The
|
||||
* user should not modify these fields.
|
||||
*
|
||||
*/
|
||||
|
||||
otSrpClientItemState mState; ///< Service state (managed by OT core).
|
||||
uint32_t mData; ///< Internal data (used by OT core).
|
||||
struct otSrpClientService *mNext; ///< Pointer to next entry in a linked-list (managed by OT core).
|
||||
const char * mName; ///< The service labels (e.g., "_mt._udp", not the full domain name).
|
||||
const char * mInstanceName; ///< The service instance name label (not the full name).
|
||||
const char *const * mSubTypeLabels; ///< Array of sub-type labels (must end with `NULL` or can be `NULL`).
|
||||
const otDnsTxtEntry * mTxtEntries; ///< Array of TXT entries (`mNumTxtEntries` gives num of entries).
|
||||
uint16_t mPort; ///< The service port number.
|
||||
uint16_t mPriority; ///< The service priority.
|
||||
uint16_t mWeight; ///< The service weight.
|
||||
uint8_t mNumTxtEntries; ///< Number of entries in the `mTxtEntries` array.
|
||||
otSrpClientItemState mState; ///< Service state (managed by OT core).
|
||||
uint32_t mData; ///< Internal data (used by OT core).
|
||||
struct otSrpClientService *mNext; ///< Pointer to next entry in a linked-list (managed by OT core).
|
||||
uint32_t mLease; ///< Desired lease interval in sec - zero to use default.
|
||||
uint32_t mKeyLease; ///< Desired key lease interval in sec - zero to use default.
|
||||
} otSrpClientService;
|
||||
|
||||
/**
|
||||
@@ -359,7 +365,9 @@ uint32_t otSrpClientGetTtl(otInstance *aInstance);
|
||||
void otSrpClientSetTtl(otInstance *aInstance, uint32_t aTtl);
|
||||
|
||||
/**
|
||||
* This function gets the lease interval used in SRP update requests.
|
||||
* This function gets the default lease interval used in SRP update requests.
|
||||
*
|
||||
* The default interval is used only for `otSrpClientService` instances with `mLease` set to zero.
|
||||
*
|
||||
* Note that this is the lease duration requested by the SRP client. The server may choose to accept a different lease
|
||||
* interval.
|
||||
@@ -372,7 +380,9 @@ void otSrpClientSetTtl(otInstance *aInstance, uint32_t aTtl);
|
||||
uint32_t otSrpClientGetLeaseInterval(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This function sets the lease interval used in SRP update requests.
|
||||
* This function sets the default lease interval used in SRP update requests.
|
||||
*
|
||||
* The default interval is used only for `otSrpClientService` instances with `mLease` set to zero.
|
||||
*
|
||||
* Changing the lease interval does not impact the accepted lease interval of already registered services/host-info.
|
||||
* It only affects any future SRP update messages (i.e., adding new services and/or refreshes of the existing services).
|
||||
@@ -385,7 +395,9 @@ uint32_t otSrpClientGetLeaseInterval(otInstance *aInstance);
|
||||
void otSrpClientSetLeaseInterval(otInstance *aInstance, uint32_t aInterval);
|
||||
|
||||
/**
|
||||
* This function gets the key lease interval used in SRP update requests.
|
||||
* This function gets the default key lease interval used in SRP update requests.
|
||||
*
|
||||
* The default interval is used only for `otSrpClientService` instances with `mKeyLease` set to zero.
|
||||
*
|
||||
* Note that this is the lease duration requested by the SRP client. The server may choose to accept a different lease
|
||||
* interval.
|
||||
@@ -398,7 +410,9 @@ void otSrpClientSetLeaseInterval(otInstance *aInstance, uint32_t aInterval);
|
||||
uint32_t otSrpClientGetKeyLeaseInterval(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This function sets the key lease interval used in SRP update requests.
|
||||
* This function sets the default key lease interval used in SRP update requests.
|
||||
*
|
||||
* The default interval is used only for `otSrpClientService` instances with `mKeyLease` set to zero.
|
||||
*
|
||||
* Changing the lease interval does not impact the accepted lease interval of already registered services/host-info.
|
||||
* It only affects any future SRP update messages (i.e., adding new services and/or refreshes of existing services).
|
||||
|
||||
@@ -131,7 +131,10 @@ my-service._ipps._tcp.default.service.arpa.
|
||||
port: 12345
|
||||
priority: 0
|
||||
weight: 0
|
||||
TXT: 00
|
||||
ttl: 7200
|
||||
lease: 7200
|
||||
key-lease: 1209600
|
||||
TXT: []
|
||||
host: my-host.default.service.arpa.
|
||||
addresses: [fded:5114:8263:1fe1:44f9:cc06:4a2d:534]
|
||||
Done
|
||||
|
||||
@@ -178,6 +178,9 @@ srp-api-test-1._ipps._tcp.default.service.arpa.
|
||||
port: 49152
|
||||
priority: 0
|
||||
weight: 0
|
||||
ttl: 7200
|
||||
lease: 7200
|
||||
key-lease: 1209600
|
||||
TXT: 0130
|
||||
host: srp-api-test-1.default.service.arpa.
|
||||
addresses: [fdde:ad00:beef:0:0:ff:fe00:fc10]
|
||||
@@ -187,6 +190,9 @@ srp-api-test-0._ipps._tcp.default.service.arpa.
|
||||
port: 49152
|
||||
priority: 0
|
||||
weight: 0
|
||||
ttl: 3600
|
||||
lease: 3600
|
||||
key-lease: 1209600
|
||||
TXT: 0130
|
||||
host: srp-api-test-0.default.service.arpa.
|
||||
addresses: [fdde:ad00:beef:0:0:ff:fe00:fc10]
|
||||
|
||||
@@ -355,7 +355,7 @@ exit:
|
||||
|
||||
otError SrpClient::ProcessServiceAdd(Arg aArgs[])
|
||||
{
|
||||
// `add` <instance-name> <service-name> <port> [priority] [weight] [txt]
|
||||
// `add` <instance-name> <service-name> <port> [priority] [weight] [txt] [lease] [key-lease]
|
||||
|
||||
otSrpClientBuffersServiceEntry *entry = nullptr;
|
||||
uint16_t size;
|
||||
@@ -417,7 +417,7 @@ otError SrpClient::ProcessServiceAdd(Arg aArgs[])
|
||||
SuccessOrExit(error = aArgs[5].ParseAsUint16(entry->mService.mWeight));
|
||||
}
|
||||
|
||||
if (!aArgs[6].IsEmpty())
|
||||
if (!aArgs[6].IsEmpty() && (aArgs[6] != "-"))
|
||||
{
|
||||
uint8_t *txtBuffer;
|
||||
|
||||
@@ -425,13 +425,23 @@ otError SrpClient::ProcessServiceAdd(Arg aArgs[])
|
||||
entry->mTxtEntry.mValueLength = size;
|
||||
|
||||
SuccessOrExit(error = aArgs[6].ParseAsHexString(entry->mTxtEntry.mValueLength, txtBuffer));
|
||||
VerifyOrExit(aArgs[7].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->mService.mNumTxtEntries = 0;
|
||||
}
|
||||
|
||||
if (!aArgs[7].IsEmpty())
|
||||
{
|
||||
SuccessOrExit(error = aArgs[7].ParseAsUint32(entry->mService.mLease));
|
||||
}
|
||||
|
||||
if (!aArgs[8].IsEmpty())
|
||||
{
|
||||
SuccessOrExit(error = aArgs[8].ParseAsUint32(entry->mService.mKeyLease));
|
||||
VerifyOrExit(aArgs[9].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = otSrpClientAddService(GetInstancePtr(), &entry->mService));
|
||||
|
||||
entry = nullptr;
|
||||
|
||||
@@ -305,6 +305,7 @@ template <> otError SrpServer::Process<Cmd("service")>(Arg aArgs[])
|
||||
const uint8_t * txtData;
|
||||
uint16_t txtDataLength;
|
||||
bool hasSubType = false;
|
||||
otSrpServerLeaseInfo leaseInfo;
|
||||
|
||||
OutputLine("%s", instanceName);
|
||||
OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false");
|
||||
@@ -314,6 +315,8 @@ template <> otError SrpServer::Process<Cmd("service")>(Arg aArgs[])
|
||||
continue;
|
||||
}
|
||||
|
||||
otSrpServerServiceGetLeaseInfo(service, &leaseInfo);
|
||||
|
||||
OutputFormat(kIndentSize, "subtypes: ");
|
||||
|
||||
while ((subService = otSrpServerHostFindNextService(
|
||||
@@ -332,7 +335,9 @@ template <> otError SrpServer::Process<Cmd("service")>(Arg aArgs[])
|
||||
OutputLine(kIndentSize, "port: %hu", otSrpServerServiceGetPort(service));
|
||||
OutputLine(kIndentSize, "priority: %hu", otSrpServerServiceGetPriority(service));
|
||||
OutputLine(kIndentSize, "weight: %hu", otSrpServerServiceGetWeight(service));
|
||||
OutputLine(kIndentSize, "ttl: %hu", otSrpServerServiceGetTtl(service));
|
||||
OutputLine(kIndentSize, "ttl: %u", otSrpServerServiceGetTtl(service));
|
||||
OutputLine(kIndentSize, "lease: %u", leaseInfo.mLease / 1000);
|
||||
OutputLine(kIndentSize, "key-lease: %u", leaseInfo.mKeyLease / 1000);
|
||||
|
||||
txtData = otSrpServerServiceGetTxtData(service, &txtDataLength);
|
||||
OutputFormat(kIndentSize, "TXT: ");
|
||||
|
||||
+225
-87
@@ -114,6 +114,9 @@ Error Client::Service::Init(void)
|
||||
// to avoid logging.
|
||||
mState = OT_SRP_CLIENT_ITEM_STATE_REMOVED;
|
||||
|
||||
mLease = Min(mLease, kMaxLease);
|
||||
mKeyLease = Min(mKeyLease, kMaxLease);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
@@ -251,15 +254,17 @@ Client::Client(Instance &aInstance)
|
||||
, mTxFailureRetryCount(0)
|
||||
, mShouldRemoveKeyLease(false)
|
||||
, mAutoHostAddressAddedMeshLocal(false)
|
||||
, mSingleServiceMode(false)
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
, mServiceKeyRecordEnabled(false)
|
||||
#endif
|
||||
, mUpdateMessageId(0)
|
||||
, mRetryWaitInterval(kMinRetryWaitInterval)
|
||||
, mAcceptedLeaseInterval(0)
|
||||
, mTtl(0)
|
||||
, mLeaseInterval(kDefaultLease)
|
||||
, mKeyLeaseInterval(kDefaultKeyLease)
|
||||
, mLease(0)
|
||||
, mKeyLease(0)
|
||||
, mDefaultLease(kDefaultLease)
|
||||
, mDefaultKeyLease(kDefaultKeyLease)
|
||||
, mSocket(aInstance)
|
||||
, mCallback(nullptr)
|
||||
, mCallbackContext(nullptr)
|
||||
@@ -336,7 +341,7 @@ void Client::Stop(Requester aRequester, StopMode aMode)
|
||||
|
||||
VerifyOrExit(GetState() != kStateStopped);
|
||||
|
||||
mSingleServiceMode.Disable();
|
||||
mSingleServiceMode = false;
|
||||
|
||||
// State changes:
|
||||
// kAdding -> kToRefresh
|
||||
@@ -344,7 +349,7 @@ void Client::Stop(Requester aRequester, StopMode aMode)
|
||||
// kRemoving -> kToRemove
|
||||
// kRegistered -> kToRefresh
|
||||
|
||||
ChangeHostAndServiceStates(kNewStateOnStop);
|
||||
ChangeHostAndServiceStates(kNewStateOnStop, kForAllServices);
|
||||
|
||||
IgnoreError(mSocket.Close());
|
||||
|
||||
@@ -406,14 +411,14 @@ void Client::Pause(void)
|
||||
/* (7) kRemoved -> */ kRemoved,
|
||||
};
|
||||
|
||||
mSingleServiceMode.Disable();
|
||||
mSingleServiceMode = false;
|
||||
|
||||
// State changes:
|
||||
// kAdding -> kToRefresh
|
||||
// kRefreshing -> kToRefresh
|
||||
// kRemoving -> kToRemove
|
||||
|
||||
ChangeHostAndServiceStates(kNewStateOnPause);
|
||||
ChangeHostAndServiceStates(kNewStateOnPause, kForAllServices);
|
||||
|
||||
SetState(kStatePaused);
|
||||
}
|
||||
@@ -705,7 +710,7 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::ChangeHostAndServiceStates(const ItemState *aNewStates)
|
||||
void Client::ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStateChangeMode aMode)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
|
||||
ItemState oldHostState = mHostInfo.GetState();
|
||||
@@ -715,7 +720,7 @@ void Client::ChangeHostAndServiceStates(const ItemState *aNewStates)
|
||||
|
||||
for (Service &service : mServices)
|
||||
{
|
||||
if (mSingleServiceMode.IsEnabled() && mSingleServiceMode.GetService() != &service)
|
||||
if ((aMode == kForServicesAppendedInMessage) && !service.IsAppendedInMessage())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -788,7 +793,7 @@ void Client::SendUpdate(void)
|
||||
if (length >= Ip6::kMaxDatagramLength)
|
||||
{
|
||||
LogInfo("Msg len %u is larger than MTU, enabling single service mode", length);
|
||||
mSingleServiceMode.Enable();
|
||||
mSingleServiceMode = true;
|
||||
IgnoreError(message->SetLength(0));
|
||||
SuccessOrExit(error = PrepareUpdateMessage(*message));
|
||||
}
|
||||
@@ -802,7 +807,7 @@ void Client::SendUpdate(void)
|
||||
// kToRefresh -> kRefreshing
|
||||
// kToRemove -> kRemoving
|
||||
|
||||
ChangeHostAndServiceStates(kNewStateOnMessageTx);
|
||||
ChangeHostAndServiceStates(kNewStateOnMessageTx, kForServicesAppendedInMessage);
|
||||
|
||||
// Remember the update message tx time to use later to determine the
|
||||
// lease renew time.
|
||||
@@ -830,7 +835,7 @@ exit:
|
||||
|
||||
LogInfo("Failed to send update: %s", ErrorToString(error));
|
||||
|
||||
mSingleServiceMode.Disable();
|
||||
mSingleServiceMode = false;
|
||||
FreeMessage(message);
|
||||
|
||||
SetState(kStateToRetry);
|
||||
@@ -900,19 +905,7 @@ Error Client::PrepareUpdateMessage(Message &aMessage)
|
||||
|
||||
// Prepare Update section
|
||||
|
||||
if ((mHostInfo.GetState() != kToRemove) && (mHostInfo.GetState() != kRemoving))
|
||||
{
|
||||
for (Service &service : mServices)
|
||||
{
|
||||
SuccessOrExit(error = AppendServiceInstructions(service, aMessage, info));
|
||||
|
||||
if (mSingleServiceMode.IsEnabled() && (mSingleServiceMode.GetService() != nullptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SuccessOrExit(error = AppendServiceInstructions(aMessage, info));
|
||||
SuccessOrExit(error = AppendHostDescriptionInstruction(aMessage, info));
|
||||
|
||||
header.SetUpdateRecordCount(info.mRecordCount);
|
||||
@@ -953,33 +946,179 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, Info &aInfo)
|
||||
Error Client::AppendServiceInstructions(Message &aMessage, Info &aInfo)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
|
||||
if ((mHostInfo.GetState() == kToRemove) || (mHostInfo.GetState() == kRemoving))
|
||||
{
|
||||
// When host is being removed, there is no need to include
|
||||
// services in the message (server is expected to remove any
|
||||
// previously registered services by this client). However, we
|
||||
// still mark all services as if they are appended in the message
|
||||
// so to ensure to update their state after sending the message.
|
||||
|
||||
for (Service &service : mServices)
|
||||
{
|
||||
service.MarkAsAppendedInMessage();
|
||||
}
|
||||
|
||||
mLease = 0;
|
||||
mKeyLease = mShouldRemoveKeyLease ? 0 : mDefaultKeyLease;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
mLease = kUnspecifiedInterval;
|
||||
mKeyLease = kUnspecifiedInterval;
|
||||
|
||||
// We first go through all services which are being updated (in any
|
||||
// of `...ing` states) and determine the lease and key lease intervals
|
||||
// associated with them. By the end of the loop either of `mLease` or
|
||||
// `mKeyLease` may be set or may still remain `kUnspecifiedInterval`.
|
||||
|
||||
for (Service &service : mServices)
|
||||
{
|
||||
uint32_t lease = DetermineLeaseInterval(service.GetLease(), mDefaultLease);
|
||||
uint32_t keyLease = Max(DetermineLeaseInterval(service.GetKeyLease(), mDefaultKeyLease), lease);
|
||||
|
||||
service.ClearAppendedInMessageFlag();
|
||||
|
||||
switch (service.GetState())
|
||||
{
|
||||
case kAdding:
|
||||
case kRefreshing:
|
||||
OT_ASSERT((mLease == kUnspecifiedInterval) || (mLease == lease));
|
||||
mLease = lease;
|
||||
|
||||
OT_FALL_THROUGH;
|
||||
|
||||
case kRemoving:
|
||||
OT_ASSERT((mKeyLease == kUnspecifiedInterval) || (mKeyLease == keyLease));
|
||||
mKeyLease = keyLease;
|
||||
break;
|
||||
|
||||
case kToAdd:
|
||||
case kToRefresh:
|
||||
case kToRemove:
|
||||
case kRegistered:
|
||||
case kRemoved:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We go through all services again and append the services that
|
||||
// match the selected `mLease` and `mKeyLease`. If the lease intervals
|
||||
// are not yet set, the first appended service will determine them.
|
||||
|
||||
for (Service &service : mServices)
|
||||
{
|
||||
// Skip over services that are already registered in this loop.
|
||||
// They may be added from the loop below once the lease intervals
|
||||
// are determined.
|
||||
|
||||
if ((service.GetState() != kRegistered) && CanAppendService(service))
|
||||
{
|
||||
SuccessOrExit(error = AppendServiceInstruction(service, aMessage, aInfo));
|
||||
|
||||
if (mSingleServiceMode)
|
||||
{
|
||||
// In "single service mode", we allow only one service
|
||||
// to be appended in the message.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mSingleServiceMode)
|
||||
{
|
||||
for (Service &service : mServices)
|
||||
{
|
||||
if ((service.GetState() == kRegistered) && CanAppendService(service) && ShouldRenewEarly(service))
|
||||
{
|
||||
// If the lease needs to be renewed or if we are close to the
|
||||
// renewal time of a registered service, we refresh the service
|
||||
// early and include it in this update. This helps put more
|
||||
// services on the same lease refresh schedule.
|
||||
|
||||
service.SetState(kToRefresh);
|
||||
SuccessOrExit(error = AppendServiceInstruction(service, aMessage, aInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `mLease` or `mKeylease` may be determined from the set of
|
||||
// services included in the message. If they are not yet set we
|
||||
// use the default intervals.
|
||||
|
||||
mLease = DetermineLeaseInterval(mLease, mDefaultLease);
|
||||
mKeyLease = DetermineLeaseInterval(mKeyLease, mDefaultKeyLease);
|
||||
|
||||
// When message only contains removal of a previously registered
|
||||
// service, then `mKeyLease` is set but `mLease` remains unspecified.
|
||||
// In such a case, we end up using `mDefaultLease` but then we need
|
||||
// to make sure it is not greater than the selected `mKeyLease`.
|
||||
|
||||
if (mLease > mKeyLease)
|
||||
{
|
||||
mLease = mKeyLease;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Client::CanAppendService(const Service &aService)
|
||||
{
|
||||
// Check the lease intervals associated with `aService` to see if
|
||||
// it can be included in this message. When removing a service,
|
||||
// only key lease interval should match. In all other cases, both
|
||||
// lease and key lease should match. The `mLease` and/or `mKeyLease`
|
||||
// may be updated if they were unspecified.
|
||||
|
||||
bool canAppend = false;
|
||||
uint32_t lease = DetermineLeaseInterval(aService.GetLease(), mDefaultLease);
|
||||
uint32_t keyLease = Max(DetermineLeaseInterval(aService.GetKeyLease(), mDefaultKeyLease), lease);
|
||||
|
||||
switch (aService.GetState())
|
||||
{
|
||||
case kToAdd:
|
||||
case kAdding:
|
||||
case kToRefresh:
|
||||
case kRefreshing:
|
||||
case kRegistered:
|
||||
VerifyOrExit((mLease == kUnspecifiedInterval) || (mLease == lease));
|
||||
VerifyOrExit((mKeyLease == kUnspecifiedInterval) || (mKeyLease == keyLease));
|
||||
mLease = lease;
|
||||
mKeyLease = keyLease;
|
||||
canAppend = true;
|
||||
break;
|
||||
|
||||
case kToRemove:
|
||||
case kRemoving:
|
||||
VerifyOrExit((mKeyLease == kUnspecifiedInterval) || (mKeyLease == keyLease));
|
||||
mKeyLease = keyLease;
|
||||
canAppend = true;
|
||||
break;
|
||||
|
||||
case kRemoved:
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return canAppend;
|
||||
}
|
||||
|
||||
Error Client::AppendServiceInstruction(Service &aService, Message &aMessage, Info &aInfo)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
bool removing = ((aService.GetState() == kToRemove) || (aService.GetState() == kRemoving));
|
||||
Dns::ResourceRecord rr;
|
||||
Dns::SrvRecord srv;
|
||||
bool removing;
|
||||
uint16_t serviceNameOffset;
|
||||
uint16_t instanceNameOffset;
|
||||
uint16_t offset;
|
||||
|
||||
if (aService.GetState() == kRegistered)
|
||||
{
|
||||
// If the lease needs to be renewed or if we are close to the
|
||||
// renewal time of a registered service, we refresh the service
|
||||
// early and include it in this update. This helps put more
|
||||
// services on the same lease refresh schedule.
|
||||
|
||||
VerifyOrExit(ShouldRenewEarly(aService));
|
||||
aService.SetState(kToRefresh);
|
||||
}
|
||||
|
||||
removing = ((aService.GetState() == kToRemove) || (aService.GetState() == kRemoving));
|
||||
|
||||
if (mSingleServiceMode.IsEnabled())
|
||||
{
|
||||
mSingleServiceMode.SetService(aService);
|
||||
}
|
||||
aService.MarkAsAppendedInMessage();
|
||||
|
||||
//----------------------------------
|
||||
// Service Discovery Instruction
|
||||
@@ -995,7 +1134,7 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In
|
||||
// to NONE and TTL to zero (RFC 2136 - section 2.5.4).
|
||||
|
||||
rr.Init(Dns::ResourceRecord::kTypePtr, removing ? Dns::PtrRecord::kClassNone : Dns::PtrRecord::kClassInternet);
|
||||
rr.SetTtl(removing ? 0 : GetTtl());
|
||||
rr.SetTtl(removing ? 0 : DetermineTtl());
|
||||
offset = aMessage.GetLength();
|
||||
SuccessOrExit(error = aMessage.Append(rr));
|
||||
|
||||
@@ -1054,7 +1193,7 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In
|
||||
|
||||
SuccessOrExit(error = Dns::Name::AppendPointerLabel(instanceNameOffset, aMessage));
|
||||
srv.Init();
|
||||
srv.SetTtl(GetTtl());
|
||||
srv.SetTtl(DetermineTtl());
|
||||
srv.SetPriority(aService.GetPriority());
|
||||
srv.SetWeight(aService.GetWeight());
|
||||
srv.SetPort(aService.GetPort());
|
||||
@@ -1154,7 +1293,7 @@ Error Client::AppendAaaaRecord(const Ip6::Address &aAddress, Message &aMessage,
|
||||
Dns::ResourceRecord rr;
|
||||
|
||||
rr.Init(Dns::ResourceRecord::kTypeAaaa);
|
||||
rr.SetTtl(GetTtl());
|
||||
rr.SetTtl(DetermineTtl());
|
||||
rr.SetLength(sizeof(Ip6::Address));
|
||||
|
||||
SuccessOrExit(error = AppendHostName(aMessage, aInfo));
|
||||
@@ -1173,7 +1312,7 @@ Error Client::AppendKeyRecord(Message &aMessage, Info &aInfo) const
|
||||
Crypto::Ecdsa::P256::PublicKey publicKey;
|
||||
|
||||
key.Init();
|
||||
key.SetTtl(GetTtl());
|
||||
key.SetTtl(DetermineTtl());
|
||||
key.SetFlags(Dns::KeyRecord::kAuthConfidPermitted, Dns::KeyRecord::kOwnerNonZone,
|
||||
Dns::KeyRecord::kSignatoryFlagGeneral);
|
||||
key.SetProtocol(Dns::KeyRecord::kProtocolDnsSec);
|
||||
@@ -1232,7 +1371,7 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Client::AppendUpdateLeaseOptRecord(Message &aMessage) const
|
||||
Error Client::AppendUpdateLeaseOptRecord(Message &aMessage)
|
||||
{
|
||||
Error error;
|
||||
Dns::OptRecord optRecord;
|
||||
@@ -1251,17 +1390,8 @@ Error Client::AppendUpdateLeaseOptRecord(Message &aMessage) const
|
||||
SuccessOrExit(error = aMessage.Append(optRecord));
|
||||
|
||||
leaseOption.Init();
|
||||
|
||||
if ((mHostInfo.GetState() == kToRemove) || (mHostInfo.GetState() == kRemoving))
|
||||
{
|
||||
leaseOption.SetLeaseInterval(0);
|
||||
leaseOption.SetKeyLeaseInterval(mShouldRemoveKeyLease ? 0 : mKeyLeaseInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
leaseOption.SetLeaseInterval(mLeaseInterval);
|
||||
leaseOption.SetKeyLeaseInterval(mKeyLeaseInterval);
|
||||
}
|
||||
leaseOption.SetLeaseInterval(mLease);
|
||||
leaseOption.SetKeyLeaseInterval(mKeyLease);
|
||||
|
||||
error = aMessage.Append(leaseOption);
|
||||
|
||||
@@ -1458,7 +1588,6 @@ void Client::ProcessResponse(Message &aMessage)
|
||||
// interval accepted by server. If not present, then use the
|
||||
// transmitted lease interval from the update request message.
|
||||
|
||||
mAcceptedLeaseInterval = mLeaseInterval;
|
||||
recordCount =
|
||||
header.GetPrerequisiteRecordCount() + header.GetUpdateRecordCount() + header.GetAdditionalRecordCount();
|
||||
|
||||
@@ -1483,13 +1612,13 @@ void Client::ProcessResponse(Message &aMessage)
|
||||
// lease interval is too short (shorter than the guard time) we
|
||||
// just use half of the accepted lease interval.
|
||||
|
||||
if (mAcceptedLeaseInterval > kLeaseRenewGuardInterval)
|
||||
if (mLease > kLeaseRenewGuardInterval)
|
||||
{
|
||||
mLeaseRenewTime += Time::SecToMsec(mAcceptedLeaseInterval - kLeaseRenewGuardInterval);
|
||||
mLeaseRenewTime += Time::SecToMsec(mLease - kLeaseRenewGuardInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLeaseRenewTime += Time::SecToMsec(mAcceptedLeaseInterval) / 2;
|
||||
mLeaseRenewTime += Time::SecToMsec(mLease) / 2;
|
||||
}
|
||||
|
||||
for (Service &service : mServices)
|
||||
@@ -1505,8 +1634,7 @@ void Client::ProcessResponse(Message &aMessage)
|
||||
// kRefreshing -> kRegistered
|
||||
// kRemoving -> kRemoved
|
||||
|
||||
ChangeHostAndServiceStates(kNewStateOnUpdateDone);
|
||||
mSingleServiceMode.Disable();
|
||||
ChangeHostAndServiceStates(kNewStateOnUpdateDone, kForServicesAppendedInMessage);
|
||||
|
||||
HandleUpdateDone();
|
||||
UpdateState();
|
||||
@@ -1585,12 +1713,8 @@ Error Client::ProcessOptRecord(const Message &aMessage, uint16_t aOffset, const
|
||||
{
|
||||
SuccessOrExit(error = aMessage.Read(aOffset, leaseOption));
|
||||
|
||||
mAcceptedLeaseInterval = leaseOption.GetLeaseInterval();
|
||||
|
||||
if (mAcceptedLeaseInterval > kMaxLease)
|
||||
{
|
||||
mAcceptedLeaseInterval = kMaxLease;
|
||||
}
|
||||
mLease = Min(leaseOption.GetLeaseInterval(), kMaxLease);
|
||||
mKeyLease = Min(leaseOption.GetKeyLeaseInterval(), kMaxLease);
|
||||
}
|
||||
|
||||
size = static_cast<uint16_t>(option.GetSize());
|
||||
@@ -1720,33 +1844,47 @@ void Client::GrowRetryWaitInterval(void)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Client::GetBoundedLeaseInterval(uint32_t aInterval, uint32_t aDefaultInterval) const
|
||||
uint32_t Client::DetermineLeaseInterval(uint32_t aInterval, uint32_t aDefaultInterval) const
|
||||
{
|
||||
uint32_t boundedInterval = aDefaultInterval;
|
||||
// Determine the lease or key lease interval.
|
||||
//
|
||||
// We use `aInterval` if it is non-zero, otherwise, use the
|
||||
// `aDefaultInterval`. We also ensure that the returned value is
|
||||
// never greater than `kMaxLease`. The `kMaxLease` is selected
|
||||
// such the lease intervals in msec can still fit in a `uint32_t`
|
||||
// `Time` variable (`kMaxLease` is ~ 24.8 days).
|
||||
|
||||
if (aInterval != 0)
|
||||
{
|
||||
boundedInterval = Min(aInterval, kMaxLease);
|
||||
}
|
||||
return Min(kMaxLease, (aInterval != kUnspecifiedInterval) ? aInterval : aDefaultInterval);
|
||||
}
|
||||
|
||||
return boundedInterval;
|
||||
uint32_t Client::DetermineTtl(void) const
|
||||
{
|
||||
// Determine the TTL to use based on current `mLease`.
|
||||
// If `mLease == 0`, it indicates we are removing host
|
||||
// and so we use `mDefaultLease` instead.
|
||||
|
||||
uint32_t lease = (mLease == 0) ? mDefaultLease : mLease;
|
||||
|
||||
return (mTtl == kUnspecifiedInterval) ? lease : Min(mTtl, lease);
|
||||
}
|
||||
|
||||
bool Client::ShouldRenewEarly(const Service &aService) const
|
||||
{
|
||||
// Check if we reached the service renew time or close to it. The
|
||||
// "early renew interval" is used to allow early refresh. It is
|
||||
// calculated as a factor of the `mAcceptedLeaseInterval`. The
|
||||
// "early lease renew factor" is given as a fraction (numerator and
|
||||
// denominator). If the denominator is set to zero (i.e., factor is
|
||||
// set to infinity), then service is always included in all SRP
|
||||
// calculated as a factor of the service requested lease interval.
|
||||
// The "early lease renew factor" is given as a fraction (numerator
|
||||
// and denominator). If the denominator is set to zero (i.e., factor
|
||||
// is set to infinity), then service is always included in all SRP
|
||||
// update messages.
|
||||
|
||||
bool shouldRenew;
|
||||
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_EARLY_LEASE_RENEW_FACTOR_DENOMINATOR != 0
|
||||
uint32_t earlyRenewInterval =
|
||||
Time::SecToMsec(mAcceptedLeaseInterval) / kEarlyLeaseRenewFactorDenominator * kEarlyLeaseRenewFactorNumerator;
|
||||
uint32_t earlyRenewInterval;
|
||||
|
||||
earlyRenewInterval = Time::SecToMsec(DetermineLeaseInterval(aService.GetLease(), mDefaultLease));
|
||||
earlyRenewInterval = earlyRenewInterval / kEarlyLeaseRenewFactorDenominator * kEarlyLeaseRenewFactorNumerator;
|
||||
|
||||
shouldRenew = (aService.GetLeaseRenewTime() <= TimerMilli::GetNow() + earlyRenewInterval);
|
||||
#else
|
||||
@@ -1771,7 +1909,7 @@ void Client::HandleTimer(void)
|
||||
break;
|
||||
|
||||
case kStateUpdating:
|
||||
mSingleServiceMode.Disable();
|
||||
mSingleServiceMode = false;
|
||||
LogRetryWaitInterval();
|
||||
LogInfo("Timed out, no response");
|
||||
GrowRetryWaitInterval();
|
||||
|
||||
+52
-31
@@ -269,17 +269,45 @@ public:
|
||||
uint8_t GetNumTxtEntries(void) const { return mNumTxtEntries; }
|
||||
|
||||
/**
|
||||
* This method get the state of service.
|
||||
* This method gets the state of service.
|
||||
*
|
||||
* @returns The service state.
|
||||
*
|
||||
*/
|
||||
ItemState GetState(void) const { return static_cast<ItemState>(mState); }
|
||||
|
||||
/**
|
||||
* This method gets the desired lease interval to request when registering this service.
|
||||
*
|
||||
* @returns The desired lease interval in sec. Zero indicates to use default.
|
||||
*
|
||||
*/
|
||||
uint32_t GetLease(void) const { return (mLease & kLeaseMask); }
|
||||
|
||||
/**
|
||||
* This method gets the desired key lease interval to request when registering this service.
|
||||
*
|
||||
* @returns The desired lease interval in sec. Zero indicates to use default.
|
||||
*
|
||||
*/
|
||||
uint32_t GetKeyLease(void) const { return mKeyLease; }
|
||||
|
||||
private:
|
||||
// We use the high (MSB) bit of `mLease` as flag to indicate
|
||||
// whether or not the service is appended in the message.
|
||||
// This is then used when updating the service state. Note that
|
||||
// we guarantee that `mLease` is not greater than `kMaxLease`
|
||||
// which ensures that the last bit is unused.
|
||||
|
||||
static constexpr uint32_t kAppendedInMsgFlag = (1U << 31);
|
||||
static constexpr uint32_t kLeaseMask = ~kAppendedInMsgFlag;
|
||||
|
||||
void SetState(ItemState aState);
|
||||
TimeMilli GetLeaseRenewTime(void) const { return TimeMilli(mData); }
|
||||
void SetLeaseRenewTime(TimeMilli aTime) { mData = aTime.GetValue(); }
|
||||
bool IsAppendedInMessage(void) const { return mLease & kAppendedInMsgFlag; }
|
||||
void MarkAsAppendedInMessage(void) { mLease |= kAppendedInMsgFlag; }
|
||||
void ClearAppendedInMessageFlag(void) { mLease &= ~kAppendedInMsgFlag; }
|
||||
bool Matches(const Service &aOther) const;
|
||||
bool Matches(ItemState aState) const { return GetState() == aState; }
|
||||
};
|
||||
@@ -446,7 +474,7 @@ public:
|
||||
* @returns The TTL (in seconds).
|
||||
*
|
||||
*/
|
||||
uint32_t GetTtl(void) const { return (0 < mTtl && mTtl < mLeaseInterval) ? mTtl : mLeaseInterval; }
|
||||
uint32_t GetTtl(void) const { return mTtl; }
|
||||
|
||||
/**
|
||||
* This method sets the TTL used in SRP update requests.
|
||||
@@ -469,7 +497,7 @@ public:
|
||||
* @returns The lease interval (in seconds).
|
||||
*
|
||||
*/
|
||||
uint32_t GetLeaseInterval(void) const { return mLeaseInterval; }
|
||||
uint32_t GetLeaseInterval(void) const { return mDefaultLease; }
|
||||
|
||||
/**
|
||||
* This method sets the lease interval used in SRP update requests.
|
||||
@@ -480,7 +508,7 @@ public:
|
||||
* @param[in] aInterval The lease interval (in seconds). If zero, the default value `kDefaultLease` would be used.
|
||||
*
|
||||
*/
|
||||
void SetLeaseInterval(uint32_t aInterval) { mLeaseInterval = GetBoundedLeaseInterval(aInterval, kDefaultLease); }
|
||||
void SetLeaseInterval(uint32_t aInterval) { mDefaultLease = DetermineLeaseInterval(aInterval, kDefaultLease); }
|
||||
|
||||
/**
|
||||
* This method gets the key lease interval used in SRP update requests.
|
||||
@@ -488,7 +516,7 @@ public:
|
||||
* @returns The key lease interval (in seconds).
|
||||
*
|
||||
*/
|
||||
uint32_t GetKeyLeaseInterval(void) const { return mKeyLeaseInterval; }
|
||||
uint32_t GetKeyLeaseInterval(void) const { return mDefaultKeyLease; }
|
||||
|
||||
/**
|
||||
* This method sets the key lease interval used in SRP update requests.
|
||||
@@ -502,7 +530,7 @@ public:
|
||||
*/
|
||||
void SetKeyLeaseInterval(uint32_t aInterval)
|
||||
{
|
||||
mKeyLeaseInterval = GetBoundedLeaseInterval(aInterval, kDefaultKeyLease);
|
||||
mDefaultKeyLease = DetermineLeaseInterval(aInterval, kDefaultKeyLease);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -851,6 +879,8 @@ private:
|
||||
// Port number to use when server is discovered using "network data anycast service".
|
||||
static constexpr uint16_t kAnycastServerPort = 53;
|
||||
|
||||
static constexpr uint32_t kUnspecifiedInterval = 0; // Used for lease/key-lease intervals.
|
||||
|
||||
// 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.
|
||||
@@ -870,24 +900,11 @@ private:
|
||||
kKeepRetryInterval,
|
||||
};
|
||||
|
||||
class SingleServiceMode
|
||||
// Used in `ChangeHostAndServiceStates()`
|
||||
enum ServiceStateChangeMode : uint8_t
|
||||
{
|
||||
public:
|
||||
SingleServiceMode(void)
|
||||
: mEnabled(false)
|
||||
, mService(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void Enable(void) { mEnabled = true, mService = nullptr; }
|
||||
void Disable(void) { mEnabled = false; }
|
||||
bool IsEnabled(void) const { return mEnabled; }
|
||||
Service *GetService(void) { return mService; }
|
||||
void SetService(Service &aService) { mService = &aService; }
|
||||
|
||||
private:
|
||||
bool mEnabled;
|
||||
Service *mService;
|
||||
kForAllServices,
|
||||
kForServicesAppendedInMessage,
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
@@ -958,20 +975,22 @@ private:
|
||||
void UpdateServiceStateToRemove(Service &aService);
|
||||
State GetState(void) const { return mState; }
|
||||
void SetState(State aState);
|
||||
void ChangeHostAndServiceStates(const ItemState *aNewStates);
|
||||
void ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStateChangeMode aMode);
|
||||
void InvokeCallback(Error aError) const;
|
||||
void InvokeCallback(Error aError, const HostInfo &aHostInfo, const Service *aRemovedServices) const;
|
||||
void HandleHostInfoOrServiceChange(void);
|
||||
void SendUpdate(void);
|
||||
Error PrepareUpdateMessage(Message &aMessage);
|
||||
Error ReadOrGenerateKey(Crypto::Ecdsa::P256::KeyPair &aKeyPair);
|
||||
Error AppendServiceInstructions(Service &aService, Message &aMessage, Info &aInfo);
|
||||
Error AppendServiceInstructions(Message &aMessage, Info &aInfo);
|
||||
bool CanAppendService(const Service &aService);
|
||||
Error AppendServiceInstruction(Service &aService, Message &aMessage, Info &aInfo);
|
||||
Error AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo);
|
||||
Error AppendKeyRecord(Message &aMessage, Info &aInfo) const;
|
||||
Error AppendDeleteAllRrsets(Message &aMessage) const;
|
||||
Error AppendHostName(Message &aMessage, Info &aInfo, bool aDoNotCompress = false) const;
|
||||
Error AppendAaaaRecord(const Ip6::Address &aAddress, Message &aMessage, Info &aInfo) const;
|
||||
Error AppendUpdateLeaseOptRecord(Message &aMessage) const;
|
||||
Error AppendUpdateLeaseOptRecord(Message &aMessage);
|
||||
Error AppendSignature(Message &aMessage, Info &aInfo);
|
||||
void UpdateRecordLengthInMessage(Dns::ResourceRecord &aRecord, uint16_t aOffset, Message &aMessage) const;
|
||||
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
||||
@@ -984,7 +1003,8 @@ private:
|
||||
uint32_t GetRetryWaitInterval(void) const { return mRetryWaitInterval; }
|
||||
void ResetRetryWaitInterval(void) { mRetryWaitInterval = kMinRetryWaitInterval; }
|
||||
void GrowRetryWaitInterval(void);
|
||||
uint32_t GetBoundedLeaseInterval(uint32_t aInterval, uint32_t aDefaultInterval) const;
|
||||
uint32_t DetermineLeaseInterval(uint32_t aInterval, uint32_t aDefaultInterval) const;
|
||||
uint32_t DetermineTtl(void) const;
|
||||
bool ShouldRenewEarly(const Service &aService) const;
|
||||
void HandleTimer(void);
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
@@ -1012,6 +1032,7 @@ private:
|
||||
uint8_t mTxFailureRetryCount : 4;
|
||||
bool mShouldRemoveKeyLease : 1;
|
||||
bool mAutoHostAddressAddedMeshLocal : 1;
|
||||
bool mSingleServiceMode : 1;
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
bool mServiceKeyRecordEnabled : 1;
|
||||
#endif
|
||||
@@ -1020,10 +1041,11 @@ private:
|
||||
uint32_t mRetryWaitInterval;
|
||||
|
||||
TimeMilli mLeaseRenewTime;
|
||||
uint32_t mAcceptedLeaseInterval;
|
||||
uint32_t mTtl;
|
||||
uint32_t mLeaseInterval;
|
||||
uint32_t mKeyLeaseInterval;
|
||||
uint32_t mLease;
|
||||
uint32_t mKeyLease;
|
||||
uint32_t mDefaultLease;
|
||||
uint32_t mDefaultKeyLease;
|
||||
|
||||
Ip6::Udp::Socket mSocket;
|
||||
|
||||
@@ -1032,7 +1054,6 @@ private:
|
||||
const char * mDomainName;
|
||||
HostInfo mHostInfo;
|
||||
LinkedList<Service> mServices;
|
||||
SingleServiceMode mSingleServiceMode;
|
||||
DelayTimer mTimer;
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
AutoStart mAutoStart;
|
||||
|
||||
@@ -198,6 +198,7 @@ EXTRA_DIST = \
|
||||
test_srp_many_services_mtu_check.py \
|
||||
test_srp_name_conflicts.py \
|
||||
test_srp_register_single_service.py \
|
||||
test_srp_register_services_diff_lease.py \
|
||||
test_srp_server_anycast_mode.py \
|
||||
test_srp_server_reboot_port.py \
|
||||
test_srp_sub_type.py \
|
||||
@@ -278,6 +279,7 @@ check_SCRIPTS = \
|
||||
test_srp_many_services_mtu_check.py \
|
||||
test_srp_name_conflicts.py \
|
||||
test_srp_register_single_service.py \
|
||||
test_srp_register_services_diff_lease.py \
|
||||
test_srp_server_anycast_mode.py \
|
||||
test_srp_server_reboot_port.py \
|
||||
test_srp_sub_type.py \
|
||||
|
||||
@@ -1023,6 +1023,8 @@ class NodeImpl:
|
||||
'priority': '0',
|
||||
'weight': '0',
|
||||
'ttl': '7200',
|
||||
'lease': '7200',
|
||||
'key-lease': '7200',
|
||||
'TXT': ['abc=010203'],
|
||||
'host_fullname': 'my-host.default.service.arpa.',
|
||||
'host': 'my-host',
|
||||
@@ -1035,6 +1037,7 @@ class NodeImpl:
|
||||
cmd = 'srp server service'
|
||||
self.send_command(cmd)
|
||||
lines = self._expect_command_output()
|
||||
|
||||
service_list = []
|
||||
while lines:
|
||||
service = {}
|
||||
@@ -1049,8 +1052,8 @@ class NodeImpl:
|
||||
service_list.append(service)
|
||||
continue
|
||||
|
||||
# 'subtypes', port', 'priority', 'weight', 'ttl'
|
||||
for i in range(0, 5):
|
||||
# 'subtypes', port', 'priority', 'weight', 'ttl', 'lease', and 'key-lease'
|
||||
for i in range(0, 7):
|
||||
key_value = lines.pop(0).strip().split(':')
|
||||
service[key_value[0].strip()] = key_value[1].strip()
|
||||
|
||||
@@ -1163,11 +1166,22 @@ class NodeImpl:
|
||||
self.send_command(f'srp client host address')
|
||||
self._expect_done()
|
||||
|
||||
def srp_client_add_service(self, instance_name, service_name, port, priority=0, weight=0, txt_entries=[]):
|
||||
def srp_client_add_service(self,
|
||||
instance_name,
|
||||
service_name,
|
||||
port,
|
||||
priority=0,
|
||||
weight=0,
|
||||
txt_entries=[],
|
||||
lease=0,
|
||||
key_lease=0):
|
||||
txt_record = "".join(self._encode_txt_entry(entry) for entry in txt_entries)
|
||||
if txt_record == '':
|
||||
txt_record = '-'
|
||||
instance_name = self._escape_escapable(instance_name)
|
||||
self.send_command(
|
||||
f'srp client service add {instance_name} {service_name} {port} {priority} {weight} {txt_record}')
|
||||
f'srp client service add {instance_name} {service_name} {port} {priority} {weight} {txt_record} {lease} {key_lease}'
|
||||
)
|
||||
self._expect_done()
|
||||
|
||||
def srp_client_remove_service(self, instance_name, service_name):
|
||||
@@ -1194,6 +1208,16 @@ class NodeImpl:
|
||||
self.send_command(cmd)
|
||||
return int(self._expect_result('\d+'))
|
||||
|
||||
def srp_client_set_key_lease_interval(self, leaseinterval: int):
|
||||
cmd = f'srp client keyleaseinterval {leaseinterval}'
|
||||
self.send_command(cmd)
|
||||
self._expect_done()
|
||||
|
||||
def srp_client_get_key_lease_interval(self) -> int:
|
||||
cmd = 'srp client keyleaseinterval'
|
||||
self.send_command(cmd)
|
||||
return int(self._expect_result('\d+'))
|
||||
|
||||
def srp_client_set_ttl(self, ttl: int):
|
||||
cmd = f'srp client ttl {ttl}'
|
||||
self.send_command(cmd)
|
||||
|
||||
@@ -0,0 +1,481 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2022, 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 config
|
||||
import thread_cert
|
||||
|
||||
# Test description:
|
||||
#
|
||||
# This test verifies the SRP client and server behavior when services
|
||||
# with different lease (and/or key lease) intervals are registered.
|
||||
#
|
||||
# Topology:
|
||||
#
|
||||
# LEADER (SRP server)
|
||||
# |
|
||||
# |
|
||||
# ROUTER (SRP client)
|
||||
#
|
||||
|
||||
SERVER = 1
|
||||
CLIENT = 2
|
||||
|
||||
|
||||
class SrpRegisterServicesDiffLease(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
SERVER: {
|
||||
'name': 'SRP_SERVER',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
CLIENT: {
|
||||
'name': 'SRP_CLIENT',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
server = self.nodes[SERVER]
|
||||
client = self.nodes[CLIENT]
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Start the server and client.
|
||||
|
||||
server.start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(server.get_state(), 'leader')
|
||||
|
||||
client.start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(client.get_state(), 'router')
|
||||
|
||||
server.srp_server_set_enabled(True)
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
client.srp_client_set_host_name('host')
|
||||
client.srp_client_enable_auto_host_address()
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Add a service with specific lease and key lease and verify that
|
||||
# it is successfully registered and seen with same lease/key-lease
|
||||
# on server.
|
||||
|
||||
client.srp_client_add_service('ins1', '_test._udp', 1111, lease=60, key_lease=800)
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
self.check_services_on_client(client, 1)
|
||||
services = server.srp_server_get_services()
|
||||
self.assertEqual(len(services), 1)
|
||||
service = services[0]
|
||||
self.assertEqual(service['fullname'], 'ins1._test._udp.default.service.arpa.')
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 60)
|
||||
self.assertEqual(int(service['lease']), 60)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Register two more services with different lease intervals.
|
||||
|
||||
client.srp_client_add_service('ins2', '_test._udp', 2222, lease=30, key_lease=200)
|
||||
client.srp_client_add_service('ins3', '_test._udp', 3333, lease=100, key_lease=1000)
|
||||
|
||||
self.simulator.go(10)
|
||||
|
||||
self.check_services_on_client(client, 3)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 3)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 60)
|
||||
self.assertEqual(int(service['lease']), 60)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 30)
|
||||
self.assertEqual(int(service['lease']), 30)
|
||||
self.assertEqual(int(service['key-lease']), 200)
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 100)
|
||||
self.assertEqual(int(service['lease']), 100)
|
||||
self.assertEqual(int(service['key-lease']), 1000)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Wait for longest lease time to validate that all services renew their
|
||||
# lease successfully.
|
||||
|
||||
self.simulator.go(105)
|
||||
|
||||
self.check_services_on_client(client, 3)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 3)
|
||||
for service in server_services:
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Remove two services.
|
||||
|
||||
client.srp_client_remove_service('ins2', '_test._udp')
|
||||
client.srp_client_remove_service('ins3', '_test._udp')
|
||||
|
||||
self.simulator.go(10)
|
||||
|
||||
self.check_services_on_client(client, 1)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 3)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 60)
|
||||
self.assertEqual(int(service['lease']), 60)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Wait for longer than key-lease of `ins2` service and check that it is
|
||||
# removed on server.
|
||||
|
||||
self.simulator.go(201)
|
||||
|
||||
self.check_services_on_client(client, 1)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 2)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 60)
|
||||
self.assertEqual(int(service['lease']), 60)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Add both services again now with same lease intervals.
|
||||
|
||||
client.srp_client_add_service('ins2', '_test._udp', 2222, lease=30, key_lease=100)
|
||||
client.srp_client_add_service('ins3', '_test._udp', 3333, lease=30, key_lease=100)
|
||||
|
||||
self.simulator.go(10)
|
||||
|
||||
self.check_services_on_client(client, 3)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 3)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 60)
|
||||
self.assertEqual(int(service['lease']), 60)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 30)
|
||||
self.assertEqual(int(service['lease']), 30)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 30)
|
||||
self.assertEqual(int(service['lease']), 30)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Remove `ins1` while adding a new service with same key-lease as
|
||||
# `ins1` but different lease interval.
|
||||
|
||||
client.srp_client_remove_service('ins1', '_test._udp')
|
||||
client.srp_client_add_service('ins4', '_test._udp', 4444, lease=90, key_lease=800)
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
self.check_services_on_client(client, 3)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 4)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 30)
|
||||
self.assertEqual(int(service['lease']), 30)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 30)
|
||||
self.assertEqual(int(service['lease']), 30)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
elif service['fullname'] == 'ins4._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 90)
|
||||
self.assertEqual(int(service['lease']), 90)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Remove two services `ins2` and `ins3` (they now have same key lease).
|
||||
|
||||
client.srp_client_remove_service('ins2', '_test._udp')
|
||||
client.srp_client_remove_service('ins3', '_test._udp')
|
||||
|
||||
self.simulator.go(10)
|
||||
|
||||
self.check_services_on_client(client, 1)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 4)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
elif service['fullname'] == 'ins4._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 90)
|
||||
self.assertEqual(int(service['lease']), 90)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Add `ins1` with key-lease smaller than lease and check that
|
||||
# client handles this properly (uses the lease value for
|
||||
# key-lease).
|
||||
|
||||
client.srp_client_add_service('ins1', '_test._udp', 1111, lease=100, key_lease=90)
|
||||
|
||||
self.simulator.go(10)
|
||||
|
||||
self.check_services_on_client(client, 2)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 4)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 100)
|
||||
self.assertEqual(int(service['lease']), 100)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'true')
|
||||
elif service['fullname'] == 'ins4._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 90)
|
||||
self.assertEqual(int(service['lease']), 90)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Change default lease and key-lease intervals on client.
|
||||
|
||||
client.srp_client_set_lease_interval(40)
|
||||
self.assertEqual(client.srp_client_get_lease_interval(), 40)
|
||||
|
||||
client.srp_client_set_key_lease_interval(330)
|
||||
self.assertEqual(client.srp_client_get_key_lease_interval(), 330)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Add `ins2` and `ins3`. `ins2` specifies the key-lease explicitly but
|
||||
# leaves lease as default. `ins3` does the opposite.
|
||||
|
||||
client.srp_client_add_service('ins2', '_test._udp', 2222, key_lease=330)
|
||||
client.srp_client_add_service('ins3', '_test._udp', 3333, lease=40)
|
||||
|
||||
self.simulator.go(10)
|
||||
|
||||
self.check_services_on_client(client, 4)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 4)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 100)
|
||||
self.assertEqual(int(service['lease']), 100)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 40)
|
||||
self.assertEqual(int(service['lease']), 40)
|
||||
self.assertEqual(int(service['key-lease']), 330)
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 40)
|
||||
self.assertEqual(int(service['lease']), 40)
|
||||
self.assertEqual(int(service['key-lease']), 330)
|
||||
elif service['fullname'] == 'ins4._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 90)
|
||||
self.assertEqual(int(service['lease']), 90)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Change the default lease to 50 and wait for long enough for `ins2`
|
||||
# and `ins3` to do lease refresh. Validate that `ins2` now requests
|
||||
# new default lease of 50 while `ins3` should stay as before.
|
||||
|
||||
client.srp_client_set_lease_interval(50)
|
||||
self.assertEqual(client.srp_client_get_lease_interval(), 50)
|
||||
|
||||
self.simulator.go(45)
|
||||
|
||||
self.check_services_on_client(client, 4)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 4)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 100)
|
||||
self.assertEqual(int(service['lease']), 100)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 50)
|
||||
self.assertEqual(int(service['lease']), 50)
|
||||
self.assertEqual(int(service['key-lease']), 330)
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 40)
|
||||
self.assertEqual(int(service['lease']), 40)
|
||||
self.assertEqual(int(service['key-lease']), 330)
|
||||
elif service['fullname'] == 'ins4._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 90)
|
||||
self.assertEqual(int(service['lease']), 90)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Change the default key lease to 30. `ins3` should adopt this but
|
||||
# since it is shorter than its explicitly specified lease the
|
||||
# client should use same value for both lease and key-lease.
|
||||
|
||||
client.srp_client_set_key_lease_interval(35)
|
||||
self.assertEqual(client.srp_client_get_key_lease_interval(), 35)
|
||||
|
||||
self.simulator.go(45)
|
||||
|
||||
self.check_services_on_client(client, 4)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 4)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 100)
|
||||
self.assertEqual(int(service['lease']), 100)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 50)
|
||||
self.assertEqual(int(service['lease']), 50)
|
||||
self.assertEqual(int(service['key-lease']), 330)
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 40)
|
||||
self.assertEqual(int(service['lease']), 40)
|
||||
self.assertEqual(int(service['key-lease']), 40)
|
||||
elif service['fullname'] == 'ins4._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 90)
|
||||
self.assertEqual(int(service['lease']), 90)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Change the requested TTL. Wait for long enough for all
|
||||
# services to refresh and check that the new TTL is correctly
|
||||
# requested by the client (when it is not larger than
|
||||
# service lease).
|
||||
|
||||
client.srp_client_set_ttl(65)
|
||||
self.assertEqual(client.srp_client_get_ttl(), 65)
|
||||
|
||||
self.simulator.go(110)
|
||||
|
||||
self.check_services_on_client(client, 4)
|
||||
server_services = server.srp_server_get_services()
|
||||
self.assertEqual(len(server_services), 4)
|
||||
for service in server_services:
|
||||
if service['fullname'] == 'ins1._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 65)
|
||||
self.assertEqual(int(service['lease']), 100)
|
||||
self.assertEqual(int(service['key-lease']), 100)
|
||||
elif service['fullname'] == 'ins2._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 50)
|
||||
self.assertEqual(int(service['lease']), 50)
|
||||
self.assertEqual(int(service['key-lease']), 330)
|
||||
elif service['fullname'] == 'ins3._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 40)
|
||||
self.assertEqual(int(service['lease']), 40)
|
||||
self.assertEqual(int(service['key-lease']), 40)
|
||||
elif service['fullname'] == 'ins4._test._udp.default.service.arpa.':
|
||||
self.assertEqual(service['deleted'], 'false')
|
||||
self.assertEqual(int(service['ttl']), 65)
|
||||
self.assertEqual(int(service['lease']), 90)
|
||||
self.assertEqual(int(service['key-lease']), 800)
|
||||
else:
|
||||
self.assertTrue(False)
|
||||
|
||||
def check_services_on_client(self, client, expected_num_services):
|
||||
services = client.srp_client_get_services()
|
||||
self.assertEqual(len(services), expected_num_services)
|
||||
for service in client.srp_client_get_services():
|
||||
self.assertIn(service['state'], ['Registered', 'ToRefresh', 'Refreshing'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
+15
-4
@@ -338,9 +338,18 @@ class Node(object):
|
||||
def srp_client_get_host_address(self):
|
||||
return self.cli('srp client host address')
|
||||
|
||||
def srp_client_add_service(self, instance_name, service_name, port, priority=0, weight=0, txt_entries=[]):
|
||||
def srp_client_add_service(self,
|
||||
instance_name,
|
||||
service_name,
|
||||
port,
|
||||
priority=0,
|
||||
weight=0,
|
||||
txt_entries=[],
|
||||
lease=0,
|
||||
key_lease=0):
|
||||
txt_record = "".join(self._encode_txt_entry(entry) for entry in txt_entries)
|
||||
self._cli_no_output('srp client service add', instance_name, service_name, port, priority, weight, txt_record)
|
||||
self._cli_no_output('srp client service add', instance_name, service_name, port, priority, weight, txt_record,
|
||||
lease, key_lease)
|
||||
|
||||
def srp_client_remove_service(self, instance_name, service_name):
|
||||
self._cli_no_output('srp client service remove', instance_name, service_name)
|
||||
@@ -462,6 +471,8 @@ class Node(object):
|
||||
'priority': '0',
|
||||
'weight': '0',
|
||||
'ttl': '7200',
|
||||
'lease': '7200',
|
||||
'key-lease', '1209600',
|
||||
'TXT': ['abc=010203'],
|
||||
'host_fullname': 'my-host.default.service.arpa.',
|
||||
'host': 'my-host',
|
||||
@@ -482,8 +493,8 @@ class Node(object):
|
||||
if service['deleted'] == 'true':
|
||||
service_list.append(service)
|
||||
continue
|
||||
# 'subtypes', port', 'priority', 'weight', 'ttl'
|
||||
for i in range(0, 5):
|
||||
# 'subtypes', port', 'priority', 'weight', 'ttl', 'lease', 'key-lease'
|
||||
for i in range(0, 7):
|
||||
key_value = outputs.pop(0).strip().split(':')
|
||||
service[key_value[0].strip()] = key_value[1].strip()
|
||||
txt_entries = outputs.pop(0).strip().split('[')[1].strip(' ]').split(',')
|
||||
|
||||
@@ -977,7 +977,7 @@ class OTCI(object):
|
||||
info['addresses'] = list(map(Ip6Addr, v.split(', ')))
|
||||
elif k == 'subtypes':
|
||||
info[k] = list() if v == '(null)' else list(v.split(','))
|
||||
elif k in ('port', 'weight', 'priority', 'ttl'):
|
||||
elif k in ('port', 'weight', 'priority', 'ttl', 'lease', 'key-lease'):
|
||||
info[k] = int(v)
|
||||
elif k in ('host',):
|
||||
info[k] = v
|
||||
|
||||
Reference in New Issue
Block a user