blob: 32d4cbbfe2fb029cfe1b296af53d0e929b3b3708 [file] [log] [blame]
/*
*
* Copyright (c) 2022 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PersistenceManager.h"
#include <lib/core/TLV.h>
#include <platform/KeyValueStoreManager.h>
using namespace chip;
CHIP_ERROR PersistenceManager::AddVideoPlayer(TargetVideoPlayerInfo * targetVideoPlayerInfo)
{
ChipLogProgress(AppServer, "PersistenceManager::AddVideoPlayer called");
VerifyOrReturnError(targetVideoPlayerInfo != nullptr && targetVideoPlayerInfo->IsInitialized(), CHIP_ERROR_INVALID_ARGUMENT);
// Read cache for video players targetted in previous runs
TargetVideoPlayerInfo cachedVideoPlayers[kMaxCachedVideoPlayers];
CHIP_ERROR err = ReadAllVideoPlayers(cachedVideoPlayers);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer,
"PersistenceManager::AddVideoPlayer status of reading previously cached video players %" CHIP_ERROR_FORMAT,
err.Format());
}
// Add active video player to the list of video players from cache
bool newVideoPlayer = true;
size_t i;
for (i = 0; i < kMaxCachedVideoPlayers && cachedVideoPlayers[i].IsInitialized(); i++)
{
// found the same video player, overwrite the data
if (cachedVideoPlayers[i] == *targetVideoPlayerInfo)
{
ChipLogProgress(AppServer,
"PersistenceManager::AddVideoPlayer found video player already cached. Overwriting at position: %lu",
static_cast<unsigned long>(i));
cachedVideoPlayers[i] = *targetVideoPlayerInfo;
newVideoPlayer = false;
}
}
if (newVideoPlayer)
{
ChipLogProgress(AppServer, "PersistenceManager::AddVideoPlayer writing new video player at position: %lu",
static_cast<unsigned long>(i));
VerifyOrReturnError(i < kMaxCachedVideoPlayers, CHIP_ERROR_BUFFER_TOO_SMALL);
cachedVideoPlayers[i] = *targetVideoPlayerInfo;
}
return WriteAllVideoPlayers(cachedVideoPlayers);
}
CHIP_ERROR PersistenceManager::WriteAllVideoPlayers(TargetVideoPlayerInfo videoPlayers[])
{
ChipLogProgress(AppServer, "PersistenceManager::WriteAllVideoPlayers called");
VerifyOrReturnError(videoPlayers != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
TLV::TLVWriter tlvWriter;
uint8_t castingData[kCastingDataMaxBytes];
tlvWriter.Init(castingData, kCastingDataMaxBytes);
TLV::TLVType outerContainerType = TLV::kTLVType_Structure;
ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kCurrentCastingDataVersionTag), kCurrentCastingDataVersion));
TLV::TLVType videoPlayersContainerType = TLV::kTLVType_Array;
// Video Players container starts
ReturnErrorOnFailure(
tlvWriter.StartContainer(TLV::ContextTag(kVideoPlayersContainerTag), TLV::kTLVType_Structure, videoPlayersContainerType));
size_t videoPlayerIndex;
for (videoPlayerIndex = 0; videoPlayerIndex < kMaxCachedVideoPlayers && videoPlayers[videoPlayerIndex].IsInitialized();
videoPlayerIndex++)
{
TargetVideoPlayerInfo * videoPlayer = &videoPlayers[videoPlayerIndex];
if (videoPlayer->IsInitialized())
{
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kNodeIdTag), videoPlayer->GetNodeId()));
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kFabricIndexTag), videoPlayer->GetFabricIndex()));
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kVideoPlayerVendorIdTag), videoPlayer->GetVendorId()));
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kVideoPlayerProductIdTag), videoPlayer->GetProductId()));
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kVideoPlayerDeviceTypeIdTag), videoPlayer->GetDeviceType()));
ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(kVideoPlayerDeviceNameTag),
(const uint8_t *) videoPlayer->GetDeviceName(),
static_cast<uint32_t>(strlen(videoPlayer->GetDeviceName()) + 1)));
ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(kVideoPlayerHostNameTag),
(const uint8_t *) videoPlayer->GetHostName(),
static_cast<uint32_t>(strlen(videoPlayer->GetHostName()) + 1)));
ReturnErrorOnFailure(
tlvWriter.Put(TLV::ContextTag(kVideoPlayerNumIPsTag), static_cast<uint64_t>(videoPlayer->GetNumIPs())));
const Inet::IPAddress * ipAddress = videoPlayer->GetIpAddresses();
if (ipAddress != nullptr && videoPlayer->GetNumIPs() > 0)
{
TLV::TLVType ipAddressesContainerType = TLV::kTLVType_Array;
// IP Addresses container starts
ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::ContextTag(kIpAddressesContainerTag), TLV::kTLVType_Structure,
ipAddressesContainerType));
for (size_t i = 0; i < videoPlayer->GetNumIPs() && i < chip::Dnssd::CommonResolutionData::kMaxIPAddresses; i++)
{
char ipAddressStr[Inet::IPAddress::kMaxStringLength];
ipAddress[i].ToString(ipAddressStr, Inet::IPAddress::kMaxStringLength);
ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(kVideoPlayerIPAddressTag),
(const uint8_t *) ipAddressStr,
static_cast<uint32_t>(strlen(ipAddressStr) + 1)));
}
// IP Addresses container ends
ReturnErrorOnFailure(tlvWriter.EndContainer(ipAddressesContainerType));
}
TargetEndpointInfo * endpoints = videoPlayer->GetEndpoints();
if (endpoints != nullptr)
{
TLV::TLVType contentAppEndpointsContainerType = TLV::kTLVType_Array;
// Content app endpoints container starts
ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::ContextTag(kContentAppEndpointsContainerTag),
TLV::kTLVType_Structure, contentAppEndpointsContainerType));
for (size_t endpointIndex = 0; endpointIndex < kMaxNumberOfEndpoints && endpoints[endpointIndex].IsInitialized();
endpointIndex++)
{
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kEndpointIdTag), endpoints[endpointIndex].GetEndpointId()));
chip::ClusterId * clusterIds = endpoints[endpointIndex].GetClusters();
if (clusterIds != nullptr)
{
TLV::TLVType clusterIdsContainerType = TLV::kTLVType_Array;
// ClusterIds container starts
ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::ContextTag(kClusterIdsContainerTag),
TLV::kTLVType_Structure, clusterIdsContainerType));
for (size_t clusterIndex = 0; clusterIndex < kMaxNumberOfClustersPerEndpoint; clusterIndex++)
{
if (clusterIds[clusterIndex] != kInvalidClusterId)
{
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kClusterIdTag), clusterIds[clusterIndex]));
}
}
// ClusterIds container ends
ReturnErrorOnFailure(tlvWriter.EndContainer(clusterIdsContainerType));
}
}
// Content app endpoints container ends
ReturnErrorOnFailure(tlvWriter.EndContainer(contentAppEndpointsContainerType));
}
}
}
// Video Players container ends
ReturnErrorOnFailure(tlvWriter.EndContainer(videoPlayersContainerType));
ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
ReturnErrorOnFailure(tlvWriter.Finalize());
ChipLogProgress(AppServer,
"PersistenceManager::WriteAllVideoPlayers TLV(CastingData).LengthWritten: %d bytes, video player count: %lu "
"and version: %d",
tlvWriter.GetLengthWritten(), static_cast<unsigned long>(videoPlayerIndex), kCurrentCastingDataVersion);
return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Put(kCastingDataKey, castingData, tlvWriter.GetLengthWritten());
}
CHIP_ERROR PersistenceManager::ReadAllVideoPlayers(TargetVideoPlayerInfo outVideoPlayers[])
{
ChipLogProgress(AppServer, "PersistenceManager::ReadAllVideoPlayers called");
VerifyOrReturnError(outVideoPlayers != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
uint8_t castingData[kCastingDataMaxBytes];
size_t castingDataSize = 0;
ReturnErrorOnFailure(chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Get(kCastingDataKey, castingData,
kCastingDataMaxBytes, &castingDataSize));
ChipLogProgress(AppServer, "PersistenceManager::ReadAllVideoPlayers Read TLV(CastingData) from KVS store with size: %lu bytes",
static_cast<unsigned long>(castingDataSize));
TLV::TLVReader reader;
reader.Init(castingData);
// read the envelope (and version)
ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
TLV::TLVType outerContainerType = TLV::kTLVType_Structure;
ReturnErrorOnFailure(reader.EnterContainer(outerContainerType));
ReturnErrorOnFailure(reader.Next());
TLV::Tag outerContainerTag = reader.GetTag();
uint8_t outerContainerTagTagNum = static_cast<uint8_t>(TLV::TagNumFromTag(outerContainerTag));
VerifyOrReturnError(outerContainerTagTagNum == kCurrentCastingDataVersionTag, CHIP_ERROR_INVALID_TLV_TAG);
uint32_t version;
ReturnErrorOnFailure(reader.Get(version));
ChipLogProgress(AppServer, "PersistenceManager::ReadAllVideoPlayers TLV(CastingData) version: %d", version);
// Entering Video Players container
TLV::TLVType videoPlayersContainerType = TLV::kTLVType_Array;
ReturnErrorOnFailure(reader.Next());
ReturnErrorOnFailure(reader.EnterContainer(videoPlayersContainerType));
size_t videoPlayerIndex = 0;
chip::NodeId nodeId = 0;
chip::FabricIndex fabricIndex = 0;
uint16_t vendorId = 0;
uint16_t productId = 0;
uint16_t deviceType = 0;
char deviceName[chip::Dnssd::kMaxDeviceNameLen + 1] = {};
char hostName[chip::Dnssd::kHostNameMaxLength + 1] = {};
size_t numIPs = 0;
Inet::IPAddress ipAddress[chip::Dnssd::CommonResolutionData::kMaxIPAddresses];
CHIP_ERROR err;
while ((err = reader.Next()) == CHIP_NO_ERROR)
{
TLV::Tag videoPlayersContainerTag = reader.GetTag();
if (!TLV::IsContextTag(videoPlayersContainerTag))
{
ChipLogError(AppServer, "Unexpected non-context TLV tag.");
return CHIP_ERROR_INVALID_TLV_TAG;
}
uint8_t videoPlayersContainerTagNum = static_cast<uint8_t>(TLV::TagNumFromTag(videoPlayersContainerTag));
if (videoPlayersContainerTagNum == kNodeIdTag)
{
ReturnErrorOnFailure(reader.Get(nodeId));
continue;
}
if (videoPlayersContainerTagNum == kFabricIndexTag)
{
ReturnErrorOnFailure(reader.Get(fabricIndex));
continue;
}
if (videoPlayersContainerTagNum == kVideoPlayerVendorIdTag)
{
ReturnErrorOnFailure(reader.Get(vendorId));
continue;
}
if (videoPlayersContainerTagNum == kVideoPlayerProductIdTag)
{
ReturnErrorOnFailure(reader.Get(productId));
continue;
}
if (videoPlayersContainerTagNum == kVideoPlayerDeviceTypeIdTag)
{
ReturnErrorOnFailure(reader.Get(deviceType));
continue;
}
if (videoPlayersContainerTagNum == kVideoPlayerDeviceNameTag)
{
ReturnErrorOnFailure(reader.GetBytes(reinterpret_cast<uint8_t *>(deviceName), chip::Dnssd::kMaxDeviceNameLen + 1));
continue;
}
if (videoPlayersContainerTagNum == kVideoPlayerHostNameTag)
{
ReturnErrorOnFailure(reader.GetBytes(reinterpret_cast<uint8_t *>(hostName), chip::Dnssd::kHostNameMaxLength + 1));
continue;
}
if (videoPlayersContainerTagNum == kVideoPlayerNumIPsTag)
{
ReturnErrorOnFailure(reader.Get(reinterpret_cast<uint64_t &>(numIPs)));
continue;
}
if (videoPlayersContainerTagNum == kIpAddressesContainerTag)
{
// Entering IP Addresses container
TLV::TLVType ipAddressesContainerType = TLV::kTLVType_Array;
ReturnErrorOnFailure(reader.EnterContainer(ipAddressesContainerType));
size_t ipCount = 0;
while ((err = reader.Next()) == CHIP_NO_ERROR)
{
TLV::Tag ipAddressesContainerTag = reader.GetTag();
if (!TLV::IsContextTag(ipAddressesContainerTag))
{
ChipLogError(AppServer, "Unexpected non-context TLV tag.");
return CHIP_ERROR_INVALID_TLV_TAG;
}
uint8_t ipAddressesContainerTagNum = static_cast<uint8_t>(TLV::TagNumFromTag(ipAddressesContainerTag));
if (ipAddressesContainerTagNum == kVideoPlayerIPAddressTag)
{
char ipAddressStr[Inet::IPAddress::kMaxStringLength];
ReturnErrorOnFailure(
reader.GetBytes(reinterpret_cast<uint8_t *>(ipAddressStr), Inet::IPAddress::kMaxStringLength));
Inet::IPAddress addressInet;
VerifyOrReturnError(Inet::IPAddress::FromString(ipAddressStr, addressInet), CHIP_ERROR_INVALID_TLV_ELEMENT);
ipAddress[ipCount] = addressInet;
ipCount++;
continue;
}
}
if (err == CHIP_END_OF_TLV)
{
// Exiting IP Addresses container
ReturnErrorOnFailure(reader.ExitContainer(ipAddressesContainerType));
continue;
}
}
if (videoPlayersContainerTagNum == kContentAppEndpointsContainerTag)
{
outVideoPlayers[videoPlayerIndex].Initialize(nodeId, fabricIndex, nullptr, nullptr, vendorId, productId, deviceType,
deviceName, hostName, numIPs, ipAddress);
// Entering Content App Endpoints container
TLV::TLVType contentAppEndpointArrayContainerType = TLV::kTLVType_Array;
ReturnErrorOnFailure(reader.EnterContainer(contentAppEndpointArrayContainerType));
// reset all endpoints
TargetEndpointInfo * endpoints = outVideoPlayers[videoPlayerIndex].GetEndpoints();
if (endpoints != nullptr)
{
for (size_t i = 0; i < kMaxNumberOfEndpoints; i++)
{
endpoints[i].Reset();
}
}
TargetEndpointInfo * endpoint = nullptr;
while ((err = reader.Next()) == CHIP_NO_ERROR)
{
TLV::Tag contentAppsContainerTag = reader.GetTag();
if (!TLV::IsContextTag(contentAppsContainerTag))
{
ChipLogError(AppServer, "Unexpected non-context TLV tag.");
return CHIP_ERROR_INVALID_TLV_TAG;
}
uint8_t contentAppsContainerTagNum = static_cast<uint8_t>(TLV::TagNumFromTag(contentAppsContainerTag));
if (contentAppsContainerTagNum == kEndpointIdTag)
{
chip::EndpointId endpointId;
ReturnErrorOnFailure(reader.Get(endpointId));
endpoint = outVideoPlayers[videoPlayerIndex].GetOrAddEndpoint(endpointId);
continue;
}
if (endpoint != nullptr && contentAppsContainerTagNum == kClusterIdsContainerTag)
{
// Entering ClusterIds container
TLV::TLVType clusterIdArrayContainerType = TLV::kTLVType_Array;
ReturnErrorOnFailure(reader.EnterContainer(clusterIdArrayContainerType));
while ((err = reader.Next()) == CHIP_NO_ERROR)
{
TLV::Tag clusterIdsContainerTag = reader.GetTag();
if (!TLV::IsContextTag(clusterIdsContainerTag))
{
ChipLogError(AppServer, "Unexpected non-context TLV tag.");
return CHIP_ERROR_INVALID_TLV_TAG;
}
uint8_t clusterIdsContainerTagNum = static_cast<uint8_t>(TLV::TagNumFromTag(clusterIdsContainerTag));
if (clusterIdsContainerTagNum == kClusterIdTag)
{
chip::ClusterId clusterId;
ReturnErrorOnFailure(reader.Get(clusterId));
if (clusterId != kInvalidClusterId)
{
endpoint->AddCluster(clusterId);
}
else
{
ChipLogError(AppServer, "PersistenceManager: ReadAllVideoPlayers ignoring invalid clusterId");
}
continue;
}
}
if (err == CHIP_END_OF_TLV)
{
// Exiting ClusterIds container
ReturnErrorOnFailure(reader.ExitContainer(clusterIdArrayContainerType));
continue;
}
}
}
if (err == CHIP_END_OF_TLV)
{
// Exiting Content App Endpoints container
ReturnErrorOnFailure(reader.ExitContainer(contentAppEndpointArrayContainerType));
videoPlayerIndex++;
continue;
}
}
}
VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
ReturnErrorOnFailure(reader.ExitContainer(videoPlayersContainerType));
ReturnErrorOnFailure(reader.ExitContainer(outerContainerType));
ChipLogProgress(AppServer, "PersistenceManager::ReadAllVideoPlayers Video player read count: %lu",
static_cast<unsigned long>(videoPlayerIndex));
return CHIP_NO_ERROR;
}
void PersistenceManager::OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex)
{
ChipLogProgress(AppServer, "PersistenceManager::OnFabricRemoved called for fabricIndex: %d", fabricIndex);
// Read cached video players
TargetVideoPlayerInfo cachedVideoPlayers[kMaxCachedVideoPlayers];
CHIP_ERROR err = ReadAllVideoPlayers(cachedVideoPlayers);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "PersistenceManager::OnFabricRemoved could not read cached video players %" CHIP_ERROR_FORMAT,
err.Format());
}
// Delete video players that match the passed in fabricIndex
for (size_t i = 0; i < kMaxCachedVideoPlayers && cachedVideoPlayers[i].IsInitialized(); i++)
{
if (cachedVideoPlayers[i].GetFabricIndex() == fabricIndex)
{
ChipLogProgress(AppServer,
"PersistenceManager::OnFabricRemoved removing video player with nodeId: 0x" ChipLogFormatX64
" from cache",
ChipLogValueX64(cachedVideoPlayers[i].GetNodeId()));
// shift elements back by 1 and mark the last array element for deletion
size_t indexToDelete = i;
if (indexToDelete + 1 < kMaxCachedVideoPlayers && cachedVideoPlayers[indexToDelete + 1].IsInitialized())
{
while (indexToDelete + 1 < kMaxCachedVideoPlayers && cachedVideoPlayers[indexToDelete + 1].IsInitialized())
{
cachedVideoPlayers[indexToDelete] = cachedVideoPlayers[indexToDelete + 1];
indexToDelete++;
}
}
// Reset cachedVideoPlayers[indexToDelete]
cachedVideoPlayers[indexToDelete].Reset();
}
}
WriteAllVideoPlayers(cachedVideoPlayers);
}
CHIP_ERROR PersistenceManager::PurgeVideoPlayerCache()
{
ChipLogProgress(AppServer, "PersistenceManager::PurgeVideoPlayerCache called");
CHIP_ERROR err = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Delete(kCastingDataKey);
if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) // no error, if the key-value pair was not stored
{
ChipLogProgress(AppServer, "PersistenceManager::PurgeVideoPlayerCache ignoring error %" CHIP_ERROR_FORMAT, err.Format());
return CHIP_NO_ERROR;
}
return err;
}