diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index 543409035..97f0a6f36 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -333,6 +333,11 @@ void Server::CommitSrpUpdate(Error aError, aHost.SetLease(grantedLease); aHost.SetKeyLease(grantedKeyLease); + for (Service::Description *desc = aHost.mServiceDescriptions.GetHead(); desc != nullptr; desc = desc->GetNext()) + { + desc->mLease = grantedLease; + desc->mKeyLease = grantedKeyLease; + } existingHost = mHosts.FindMatching(aHost.GetFullName()); @@ -1239,7 +1244,12 @@ void Server::HandleLeaseTimer(void) { next = service->GetNext(); - if (service->mIsDeleted) + if (service->GetKeyExpireTime() <= now) + { + service->Log(Service::kKeyLeaseExpired); + host->RemoveService(service, /* aRetainName */ false, /* aNotifyServiceHandler */ true); + } + else if (service->mIsDeleted) { // The service has been deleted but the name retains. earliestExpireTime = OT_MIN(earliestExpireTime, service->GetKeyExpireTime()); @@ -1262,6 +1272,7 @@ void Server::HandleLeaseTimer(void) if (earliestExpireTime != now.GetDistantFuture()) { + OT_ASSERT(earliestExpireTime >= now); if (!mLeaseTimer.IsRunning() || earliestExpireTime <= mLeaseTimer.GetFireTime()) { otLogInfoSrp("[server] lease timer is scheduled for %u seconds", Time::MsecToSec(earliestExpireTime - now)); @@ -1362,12 +1373,12 @@ TimeMilli Server::Service::GetExpireTime(void) const OT_ASSERT(!mIsDeleted); OT_ASSERT(!GetHost().IsDeleted()); - return mTimeLastUpdate + Time::SecToMsec(GetHost().GetLease()); + return mTimeLastUpdate + Time::SecToMsec(mDescription.mLease); } TimeMilli Server::Service::GetKeyExpireTime(void) const { - return mTimeLastUpdate + Time::SecToMsec(GetHost().GetKeyLease()); + return mTimeLastUpdate + Time::SecToMsec(mDescription.mKeyLease); } bool Server::Service::MatchesFlags(Flags aFlags) const @@ -1475,6 +1486,8 @@ Server::Service::Description::Description(Host &aHost) , mPort(0) , mTxtLength(0) , mTxtData(nullptr) + , mLease(0) + , mKeyLease(0) , mTimeLastUpdate(TimerMilli::GetNow().GetDistantPast()) { } @@ -1501,6 +1514,8 @@ void Server::Service::Description::TakeResourcesFrom(Description &aDescription) mWeight = aDescription.mWeight; mPort = aDescription.mPort; + mLease = aDescription.mLease; + mKeyLease = aDescription.mKeyLease; mTimeLastUpdate = TimerMilli::GetNow(); } diff --git a/src/core/net/srp_server.hpp b/src/core/net/srp_server.hpp index cdadcb1b0..9bf6ac1e4 100644 --- a/src/core/net/srp_server.hpp +++ b/src/core/net/srp_server.hpp @@ -287,6 +287,8 @@ public: uint16_t mPort; uint16_t mTxtLength; uint8_t * mTxtData; + uint32_t mLease; // The LEASE time in seconds. + uint32_t mKeyLease; // The KEY-LEASE time in seconds. TimeMilli mTimeLastUpdate; }; diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 96b25db07..d45bc12ed 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -1010,6 +1010,10 @@ class NodeImpl: self.send_command(f'srp client service remove {instance_name} {service_name}') self._expect_done() + def srp_client_clear_service(self, instance_name, service_name): + self.send_command(f'srp client service clear {instance_name} {service_name}') + self._expect_done() + def srp_client_get_services(self): cmd = 'srp client service' self.send_command(cmd) diff --git a/tests/scripts/thread-cert/test_srp_lease.py b/tests/scripts/thread-cert/test_srp_lease.py index 759f8a8ac..b2252e662 100755 --- a/tests/scripts/thread-cert/test_srp_lease.py +++ b/tests/scripts/thread-cert/test_srp_lease.py @@ -135,6 +135,44 @@ class SrpRegisterSingleService(thread_cert.TestCase): self.check_host_and_service(server, client) + # + # 4. Clear the first service, shorten the lease time and register a second service. + # Verify that the lease time of the first service is not affected by new SRP + # registrations. + # + + client.srp_client_clear_service('my-service', '_ipps._tcp') + server.srp_server_set_lease_range(50 * LEASE, 50 * LEASE, 50 * KEY_LEASE, 50 * KEY_LEASE) + client.srp_client_add_service('my-service2', '_ipps._tcp', 12345) + + # Wait for the first service to expire. + self.simulator.go(LEASE + 2) + self.assertEqual(server.srp_server_get_service('my-service', '_ipps._tcp')['deleted'], 'true') + + # Wait for the first service to be fully removed. + self.simulator.go(KEY_LEASE - LEASE + 2) + self.assertEqual(len(server.srp_server_get_services()), 1) + self.assertEqual(len(server.srp_server_get_hosts()), 1) + + # + # 5. Clear the second service, lengthen the lease time and register a third service. + # Verify that the lease time of the second service is not affected by new SRP + # registrations. + # + + client.srp_client_clear_service('my-service2', '_ipps._tcp') + server.srp_server_set_lease_range(LEASE, LEASE, KEY_LEASE, KEY_LEASE) + client.srp_client_add_service('my-service3', '_ipps._tcp', 12345) + + # The second service has lease time of 50 * LEASE and should not expire. + self.simulator.go(LEASE + 2) + self.assertEqual(server.srp_server_get_service('my-service2', '_ipps._tcp')['deleted'], 'false') + + # The second service has key-lease time of 50 * KEY_LEASE and should not expire. + self.simulator.go(KEY_LEASE - LEASE + 2) + self.assertEqual(len(server.srp_server_get_services()), 2) + self.assertEqual(len(server.srp_server_get_hosts()), 1) + def check_host_and_service(self, server, client): """Check that we have properly registered host and service instance. """