Skip to content

Commit 42570fa

Browse files
ReadClient: Truncate data version list during encoding if necessary
The existing code made the assumption that if a list of versions was able to fit into the request packet when generating the first subscribe request, then any resubscribe containing data versions for the same clusters would also fit. However the data version numbers themselves can be updated when we receive reports, and this can cause the list to no longer fit the request packet, leaving us in a state where every resubscribe attempt would fail. Note that this change means even an initial subscribe request with a data version list that is too long will no longer fail; ReadClient will simply truncate the list as needed in all cases.
1 parent b274320 commit 42570fa

File tree

2 files changed

+40
-14
lines changed

2 files changed

+40
-14
lines changed

src/app/ReadClient.cpp

+35-14
Original file line numberDiff line numberDiff line change
@@ -423,33 +423,54 @@ CHIP_ERROR ReadClient::BuildDataVersionFilterList(DataVersionFilterIBs::Builder
423423
continue;
424424
}
425425

426-
DataVersionFilterIB::Builder & filterIB = aDataVersionFilterIBsBuilder.CreateDataVersionFilter();
427-
ReturnErrorOnFailure(aDataVersionFilterIBsBuilder.GetError());
428-
ClusterPathIB::Builder & path = filterIB.CreatePath();
429-
ReturnErrorOnFailure(filterIB.GetError());
430-
ReturnErrorOnFailure(path.Endpoint(filter.mEndpointId).Cluster(filter.mClusterId).EndOfClusterPathIB());
431-
VerifyOrReturnError(filter.mDataVersion.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
432-
ReturnErrorOnFailure(filterIB.DataVersion(filter.mDataVersion.Value()).EndOfDataVersionFilterIB());
433-
aEncodedDataVersionList = true;
426+
TLV::TLVWriter backup;
427+
aDataVersionFilterIBsBuilder.Checkpoint(backup);
428+
CHIP_ERROR err = EncodeDataVersionFilter(aDataVersionFilterIBsBuilder, filter);
429+
if (err == CHIP_NO_ERROR)
430+
{
431+
aEncodedDataVersionList = true;
432+
}
433+
else if (err == CHIP_ERROR_NO_MEMORY)
434+
{
435+
// Packet is full, ignore the rest of the list
436+
aDataVersionFilterIBsBuilder.Rollback(backup);
437+
return CHIP_NO_ERROR;
438+
}
439+
else
440+
{
441+
return err;
442+
}
434443
}
435444
return CHIP_NO_ERROR;
436445
}
437446

447+
CHIP_ERROR ReadClient::EncodeDataVersionFilter(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
448+
DataVersionFilter const & aFilter)
449+
{
450+
// Caller has checked aFilter.IsValidDataVersionFilter()
451+
DataVersionFilterIB::Builder & filterIB = aDataVersionFilterIBsBuilder.CreateDataVersionFilter();
452+
ReturnErrorOnFailure(aDataVersionFilterIBsBuilder.GetError());
453+
ClusterPathIB::Builder & path = filterIB.CreatePath();
454+
ReturnErrorOnFailure(filterIB.GetError());
455+
ReturnErrorOnFailure(path.Endpoint(aFilter.mEndpointId).Cluster(aFilter.mClusterId).EndOfClusterPathIB());
456+
ReturnErrorOnFailure(filterIB.DataVersion(aFilter.mDataVersion.Value()).EndOfDataVersionFilterIB());
457+
return CHIP_NO_ERROR;
458+
}
459+
438460
CHIP_ERROR ReadClient::GenerateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
439461
const Span<AttributePathParams> & aAttributePaths,
440462
const Span<DataVersionFilter> & aDataVersionFilters,
441463
bool & aEncodedDataVersionList)
442464
{
443-
if (!aDataVersionFilters.empty())
465+
// Give the callback a chance first, otherwise use the list we have.
466+
ReturnErrorOnFailure(
467+
mpCallback.OnUpdateDataVersionFilterList(aDataVersionFilterIBsBuilder, aAttributePaths, aEncodedDataVersionList));
468+
469+
if (!aEncodedDataVersionList)
444470
{
445471
ReturnErrorOnFailure(BuildDataVersionFilterList(aDataVersionFilterIBsBuilder, aAttributePaths, aDataVersionFilters,
446472
aEncodedDataVersionList));
447473
}
448-
else
449-
{
450-
ReturnErrorOnFailure(
451-
mpCallback.OnUpdateDataVersionFilterList(aDataVersionFilterIBsBuilder, aAttributePaths, aEncodedDataVersionList));
452-
}
453474

454475
return CHIP_NO_ERROR;
455476
}

src/app/ReadClient.h

+5
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,9 @@ class ReadClient : public Messaging::ExchangeDelegate
339339
* This will send either a Read Request or a Subscribe Request depending on
340340
* the InteractionType this read client was initialized with.
341341
*
342+
* If the requests contains more data version filters than can fit in the request packet
343+
* the list will be truncated as needed, i.e. filter inclusion is on a best effort basis.
344+
*
342345
* @retval #others fail to send read request
343346
* @retval #CHIP_NO_ERROR On success.
344347
*/
@@ -559,6 +562,8 @@ class ReadClient : public Messaging::ExchangeDelegate
559562
CHIP_ERROR BuildDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
560563
const Span<AttributePathParams> & aAttributePaths,
561564
const Span<DataVersionFilter> & aDataVersionFilters, bool & aEncodedDataVersionList);
565+
CHIP_ERROR EncodeDataVersionFilter(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
566+
DataVersionFilter const & aFilter);
562567
CHIP_ERROR ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader && aReader, PeerType & aType);
563568
CHIP_ERROR ProcessAttributeReportIBs(TLV::TLVReader & aAttributeDataIBsReader);
564569
CHIP_ERROR ProcessEventReportIBs(TLV::TLVReader & aEventReportIBsReader);

0 commit comments

Comments
 (0)