mirror of
https://github.com/espressif/openthread.git
synced 2026-08-15 07:07:46 +00:00
[mdns] implement response aggregation (#10881)
This commit implements response aggregation (RFC 6762 section 6.4) in the mDNS module. If multiple responses are scheduled to be sent, each delayed by a different interval, earlier responses are further delayed to allow aggregation with other responses scheduled to go out a little later. Before preparing a response, we determine the next multicast transmission time that is explicitly after the current time. This is used for response aggregation. As the response is being prepared, different entries can decide whether to extend their answer delay duration if allowed (e.g., probe question answer delay cannot be extended) and possible (not extending the delay beyond the maximum allowed delay). To realize this, the way we track the `AnswerTime` of records is changed. It is now tracked by two variables: `mQueryRxTime` (the receive time of the question triggering the answer) and `mAnswerDelay`. This commit also adds `TestResponseAggregation()` to the `test_mdns` unit test to validate the response aggregation behavior.
This commit is contained in:
@@ -4048,6 +4048,158 @@ void TestMultiPacket(void)
|
||||
testFreeInstance(sInstance);
|
||||
}
|
||||
|
||||
void TestResponseAggregation(void)
|
||||
{
|
||||
Core *mdns = InitTest();
|
||||
Core::Service tcpService;
|
||||
Core::Service udpService;
|
||||
const DnsMessage *dnsMsg;
|
||||
uint16_t heapAllocations;
|
||||
DnsNameString fullTcpServiceName;
|
||||
DnsNameString fullTcpServiceType;
|
||||
DnsNameString fullUdpServiceName;
|
||||
DnsNameString fullUdpServiceType;
|
||||
|
||||
Log("-------------------------------------------------------------------------------------------");
|
||||
Log("TestResponseAggregation");
|
||||
|
||||
AdvanceTime(1);
|
||||
|
||||
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
||||
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
||||
|
||||
tcpService.mHostName = "host";
|
||||
tcpService.mServiceInstance = "srv1";
|
||||
tcpService.mServiceType = "_matter._tcp";
|
||||
tcpService.mSubTypeLabels = nullptr;
|
||||
tcpService.mSubTypeLabelsLength = 0;
|
||||
tcpService.mTxtData = kTxtData1;
|
||||
tcpService.mTxtDataLength = sizeof(kTxtData1);
|
||||
tcpService.mPort = 1111;
|
||||
tcpService.mPriority = 1;
|
||||
tcpService.mWeight = 2;
|
||||
tcpService.mTtl = 4500;
|
||||
|
||||
udpService.mHostName = "host";
|
||||
udpService.mServiceInstance = "srv2";
|
||||
udpService.mServiceType = "_srv._udp";
|
||||
udpService.mSubTypeLabels = nullptr;
|
||||
udpService.mSubTypeLabelsLength = 0;
|
||||
udpService.mTxtData = kTxtData2;
|
||||
udpService.mTxtDataLength = sizeof(kTxtData2);
|
||||
udpService.mPort = 2222;
|
||||
udpService.mPriority = 6;
|
||||
udpService.mWeight = 2;
|
||||
udpService.mTtl = 4500;
|
||||
|
||||
fullTcpServiceName.Append("%s.%s.local.", tcpService.mServiceInstance, tcpService.mServiceType);
|
||||
fullTcpServiceType.Append("%s.local.", tcpService.mServiceType);
|
||||
|
||||
fullUdpServiceName.Append("%s.%s.local.", udpService.mServiceInstance, udpService.mServiceType);
|
||||
fullUdpServiceType.Append("%s.local.", udpService.mServiceType);
|
||||
|
||||
Log("-------------------------------------------------------------------------------------------");
|
||||
Log("Register a first `ServiceEntry`, check probes and announcements");
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
sRegCallbacks[0].Reset();
|
||||
SuccessOrQuit(mdns->RegisterService(tcpService, 0, HandleSuccessCallback));
|
||||
|
||||
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
||||
{
|
||||
sDnsMessages.Clear();
|
||||
|
||||
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
||||
AdvanceTime(250);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
||||
dnsMsg->ValidateAsProbeFor(tcpService, /* aUnicastRequest */ (probeCount == 0));
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
}
|
||||
|
||||
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
||||
{
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
||||
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(tcpService, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
||||
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
}
|
||||
|
||||
Log("-------------------------------------------------------------------------------------------");
|
||||
Log("Register a second `ServiceEntry`, check probes and announcements");
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
sRegCallbacks[0].Reset();
|
||||
SuccessOrQuit(mdns->RegisterService(udpService, 0, HandleSuccessCallback));
|
||||
|
||||
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
||||
{
|
||||
sDnsMessages.Clear();
|
||||
|
||||
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
||||
AdvanceTime(250);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
||||
dnsMsg->ValidateAsProbeFor(udpService, /* aUnicastRequest */ (probeCount == 0));
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
}
|
||||
|
||||
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
||||
{
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
||||
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(udpService, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
}
|
||||
|
||||
Log("-------------------------------------------------------------------------------------------");
|
||||
Log("Send two PTR queries back to back and validate the response is aggregated");
|
||||
|
||||
AdvanceTime(2000);
|
||||
|
||||
sDnsMessages.Clear();
|
||||
SendQuery(fullTcpServiceType.AsCString(), ResourceRecord::kTypePtr);
|
||||
AdvanceTime(5);
|
||||
SendQuery(fullUdpServiceType.AsCString(), ResourceRecord::kTypePtr);
|
||||
|
||||
AdvanceTime(1000);
|
||||
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
VerifyOrQuit(dnsMsg != nullptr);
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 4);
|
||||
dnsMsg->Validate(tcpService, kInAnswerSection, kCheckPtr);
|
||||
dnsMsg->Validate(tcpService, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
||||
dnsMsg->Validate(udpService, kInAnswerSection, kCheckPtr);
|
||||
dnsMsg->Validate(udpService, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
|
||||
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
||||
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
||||
|
||||
Log("End of test");
|
||||
|
||||
testFreeInstance(sInstance);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void TestQuestionUnicastDisallowed(void)
|
||||
@@ -7124,6 +7276,7 @@ int main(void)
|
||||
ot::Dns::Multicast::TestHostOrServiceAndKeyReg();
|
||||
ot::Dns::Multicast::TestQuery();
|
||||
ot::Dns::Multicast::TestMultiPacket();
|
||||
ot::Dns::Multicast::TestResponseAggregation();
|
||||
ot::Dns::Multicast::TestQuestionUnicastDisallowed();
|
||||
ot::Dns::Multicast::TestTxMessageSizeLimit();
|
||||
ot::Dns::Multicast::TestHostConflict();
|
||||
|
||||
Reference in New Issue
Block a user