blob: e4db190c5076088cd22924b94ed2586d1b8c5e3e [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* 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 <app/server/Server.h>
#include <access/examples/ExampleAccessControlDelegate.h>
#include <app/AppConfig.h>
#include <app/EventManagement.h>
#include <app/InteractionModelEngine.h>
#include <app/data-model-provider/Provider.h>
#include <app/server/Dnssd.h>
#include <app/server/EchoHandler.h>
#include <app/util/DataModelHandler.h>
#include <app/util/ember-compatibility-functions.h>
#if CONFIG_NETWORK_LAYER_BLE
#include <ble/Ble.h>
#endif
#include <inet/IPAddress.h>
#include <inet/InetError.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/dnssd/Advertiser.h>
#include <lib/dnssd/ServiceNaming.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/DefaultStorageKeyAllocator.h>
#include <lib/support/PersistedCounter.h>
#include <lib/support/TestGroupData.h>
#include <lib/support/logging/CHIPLogging.h>
#include <messaging/ExchangeMgr.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/DeviceControlServer.h>
#include <platform/DeviceInfoProvider.h>
#include <platform/KeyValueStoreManager.h>
#include <platform/LockTracker.h>
#include <protocols/secure_channel/CASEServer.h>
#include <protocols/secure_channel/MessageCounterManager.h>
#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID)
#include <setup_payload/AdditionalDataPayloadGenerator.h>
#endif
#include <setup_payload/SetupPayload.h>
#include <sys/param.h>
#include <system/SystemPacketBuffer.h>
#include <system/TLVPacketBufferBackingStore.h>
#include <transport/SessionManager.h>
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
#include <transport/raw/WiFiPAF.h>
#endif
#if defined(CHIP_SUPPORT_ENABLE_STORAGE_API_AUDIT) || defined(CHIP_SUPPORT_ENABLE_STORAGE_LOAD_TEST_AUDIT)
#include <lib/support/PersistentStorageAudit.h>
#endif // defined(CHIP_SUPPORT_ENABLE_STORAGE_API_AUDIT) || defined(CHIP_SUPPORT_ENABLE_STORAGE_LOAD_TEST_AUDIT)
using namespace chip::DeviceLayer;
using chip::kMinValidFabricIndex;
using chip::RendezvousInformationFlag;
using chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr;
using chip::Inet::IPAddressType;
#if CONFIG_NETWORK_LAYER_BLE
using chip::Transport::BleListenParameters;
#endif
using chip::Transport::PeerAddress;
using chip::Transport::UdpListenParameters;
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
using chip::Transport::TcpListenParameters;
#endif
namespace {
#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
class DeviceTypeResolver : public chip::Access::AccessControl::DeviceTypeResolver
{
public:
bool IsDeviceTypeOnEndpoint(chip::DeviceTypeId deviceType, chip::EndpointId endpoint) override
{
chip::app::DataModel::Provider * model = chip::app::InteractionModelEngine::GetInstance()->GetDataModelProvider();
for (auto type = model->FirstDeviceType(endpoint); type.has_value(); type = model->NextDeviceType(endpoint, *type))
{
if (type->deviceTypeId == deviceType)
{
#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
VerifyOrDie(chip::app::IsDeviceTypeOnEndpoint(deviceType, endpoint));
#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL
return true;
}
}
#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
VerifyOrDie(!chip::app::IsDeviceTypeOnEndpoint(deviceType, endpoint));
#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL
return false;
}
} sDeviceTypeResolver;
#else // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
// Ember implementation of the device type resolver
class DeviceTypeResolver : public chip::Access::AccessControl::DeviceTypeResolver
{
public:
bool IsDeviceTypeOnEndpoint(chip::DeviceTypeId deviceType, chip::EndpointId endpoint) override
{
return chip::app::IsDeviceTypeOnEndpoint(deviceType, endpoint);
}
} sDeviceTypeResolver;
#endif
} // namespace
namespace chip {
Server Server::sServer;
#if CHIP_CONFIG_ENABLE_SERVER_IM_EVENT
#define CHIP_NUM_EVENT_LOGGING_BUFFERS 3
static uint8_t sInfoEventBuffer[CHIP_DEVICE_CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE];
static uint8_t sDebugEventBuffer[CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE];
static uint8_t sCritEventBuffer[CHIP_DEVICE_CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE];
static ::chip::PersistedCounter<chip::EventNumber> sGlobalEventIdCounter;
static ::chip::app::CircularEventBuffer sLoggingBuffer[CHIP_NUM_EVENT_LOGGING_BUFFERS];
#endif // CHIP_CONFIG_ENABLE_SERVER_IM_EVENT
CHIP_ERROR Server::Init(const ServerInitParams & initParams)
{
ChipLogProgress(AppServer, "Server initializing...");
assertChipStackLockedByCurrentThread();
mInitTimestamp = System::SystemClock().GetMonotonicMicroseconds64();
CASESessionManagerConfig caseSessionManagerConfig;
DeviceLayer::DeviceInfoProvider * deviceInfoprovider = nullptr;
mOperationalServicePort = initParams.operationalServicePort;
mUserDirectedCommissioningPort = initParams.userDirectedCommissioningPort;
mInterfaceId = initParams.interfaceId;
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrExit(initParams.persistentStorageDelegate != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(initParams.accessDelegate != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(initParams.aclStorage != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(initParams.groupDataProvider != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(initParams.sessionKeystore != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(initParams.operationalKeystore != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(initParams.opCertStore != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(initParams.reportScheduler != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
// TODO(16969): Remove chip::Platform::MemoryInit() call from Server class, it belongs to outer code
chip::Platform::MemoryInit();
// Initialize PersistentStorageDelegate-based storage
mDeviceStorage = initParams.persistentStorageDelegate;
mSessionResumptionStorage = initParams.sessionResumptionStorage;
mSubscriptionResumptionStorage = initParams.subscriptionResumptionStorage;
mOperationalKeystore = initParams.operationalKeystore;
mOpCertStore = initParams.opCertStore;
mSessionKeystore = initParams.sessionKeystore;
if (initParams.certificateValidityPolicy)
{
mCertificateValidityPolicy.Init(initParams.certificateValidityPolicy);
}
else
{
mCertificateValidityPolicy.Init(&sDefaultCertValidityPolicy);
}
#if defined(CHIP_SUPPORT_ENABLE_STORAGE_API_AUDIT)
VerifyOrDie(chip::audit::ExecutePersistentStorageApiAudit(*mDeviceStorage));
#endif
#if defined(CHIP_SUPPORT_ENABLE_STORAGE_LOAD_TEST_AUDIT)
VerifyOrDie(chip::audit::ExecutePersistentStorageLoadTestAudit(*mDeviceStorage));
#endif
// Set up attribute persistence before we try to bring up the data model
// handler.
SuccessOrExit(err = mAttributePersister.Init(mDeviceStorage));
SetAttributePersistenceProvider(&mAttributePersister);
SetSafeAttributePersistenceProvider(&mAttributePersister);
{
FabricTable::InitParams fabricTableInitParams;
fabricTableInitParams.storage = mDeviceStorage;
fabricTableInitParams.operationalKeystore = mOperationalKeystore;
fabricTableInitParams.opCertStore = mOpCertStore;
err = mFabrics.Init(fabricTableInitParams);
SuccessOrExit(err);
}
SuccessOrExit(err = mAccessControl.Init(initParams.accessDelegate, sDeviceTypeResolver));
Access::SetAccessControl(mAccessControl);
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
if (initParams.accessRestrictionProvider != nullptr)
{
mAccessControl.SetAccessRestrictionProvider(initParams.accessRestrictionProvider);
}
#endif
mAclStorage = initParams.aclStorage;
SuccessOrExit(err = mAclStorage->Init(*mDeviceStorage, mFabrics.begin(), mFabrics.end()));
mGroupsProvider = initParams.groupDataProvider;
SetGroupDataProvider(mGroupsProvider);
mReportScheduler = initParams.reportScheduler;
mTestEventTriggerDelegate = initParams.testEventTriggerDelegate;
if (mTestEventTriggerDelegate == nullptr)
{
ChipLogProgress(AppServer, "WARNING: mTestEventTriggerDelegate is null");
}
deviceInfoprovider = DeviceLayer::GetDeviceInfoProvider();
if (deviceInfoprovider)
{
deviceInfoprovider->SetStorageDelegate(mDeviceStorage);
}
// Init transport before operations with secure session mgr.
err = mTransports.Init(UdpListenParameters(DeviceLayer::UDPEndPointManager())
.SetAddressType(IPAddressType::kIPv6)
.SetListenPort(mOperationalServicePort)
.SetNativeParams(initParams.endpointNativeParams)
#if INET_CONFIG_ENABLE_IPV4
,
UdpListenParameters(DeviceLayer::UDPEndPointManager())
.SetAddressType(IPAddressType::kIPv4)
.SetListenPort(mOperationalServicePort)
#endif
#if CONFIG_NETWORK_LAYER_BLE
,
BleListenParameters(DeviceLayer::ConnectivityMgr().GetBleLayer())
#endif
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
,
TcpListenParameters(DeviceLayer::TCPEndPointManager())
.SetAddressType(IPAddressType::kIPv6)
.SetListenPort(mOperationalServicePort)
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
,
Transport::WiFiPAFListenParameters(DeviceLayer::ConnectivityMgr().GetWiFiPAF())
#endif
);
SuccessOrExit(err);
err = mListener.Init(this);
SuccessOrExit(err);
mGroupsProvider->SetListener(&mListener);
#if CONFIG_NETWORK_LAYER_BLE
mBleLayer = DeviceLayer::ConnectivityMgr().GetBleLayer();
#endif
SuccessOrExit(err);
err = mSessions.Init(&DeviceLayer::SystemLayer(), &mTransports, &mMessageCounterManager, mDeviceStorage, &GetFabricTable(),
*mSessionKeystore);
SuccessOrExit(err);
err = mFabricDelegate.Init(this);
SuccessOrExit(err);
mFabrics.AddFabricDelegate(&mFabricDelegate);
err = mExchangeMgr.Init(&mSessions);
SuccessOrExit(err);
err = mMessageCounterManager.Init(&mExchangeMgr);
SuccessOrExit(err);
err = mUnsolicitedStatusHandler.Init(&mExchangeMgr);
SuccessOrExit(err);
SuccessOrExit(err = mCommissioningWindowManager.Init(this));
mCommissioningWindowManager.SetAppDelegate(initParams.appDelegate);
app::DnssdServer::Instance().SetFabricTable(&mFabrics);
app::DnssdServer::Instance().SetCommissioningModeProvider(&mCommissioningWindowManager);
chip::Dnssd::Resolver::Instance().Init(DeviceLayer::UDPEndPointManager());
#if CHIP_CONFIG_ENABLE_SERVER_IM_EVENT
// Initialize event logging subsystem
err = sGlobalEventIdCounter.Init(mDeviceStorage, DefaultStorageKeyAllocator::IMEventNumber(),
CHIP_DEVICE_CONFIG_EVENT_ID_COUNTER_EPOCH);
SuccessOrExit(err);
{
::chip::app::LogStorageResources logStorageResources[] = {
{ &sDebugEventBuffer[0], sizeof(sDebugEventBuffer), ::chip::app::PriorityLevel::Debug },
{ &sInfoEventBuffer[0], sizeof(sInfoEventBuffer), ::chip::app::PriorityLevel::Info },
{ &sCritEventBuffer[0], sizeof(sCritEventBuffer), ::chip::app::PriorityLevel::Critical }
};
chip::app::EventManagement::GetInstance().Init(&mExchangeMgr, CHIP_NUM_EVENT_LOGGING_BUFFERS, &sLoggingBuffer[0],
&logStorageResources[0], &sGlobalEventIdCounter,
std::chrono::duration_cast<System::Clock::Milliseconds64>(mInitTimestamp));
}
#endif // CHIP_CONFIG_ENABLE_SERVER_IM_EVENT
// This initializes clusters, so should come after lower level initialization.
InitDataModelHandler();
#if defined(CHIP_APP_USE_ECHO)
err = InitEchoHandler(&mExchangeMgr);
SuccessOrExit(err);
#endif
//
// We need to advertise the port that we're listening to for unsolicited messages over UDP. However, we have both a IPv4
// and IPv6 endpoint to pick from. Given that the listen port passed in may be set to 0 (which then has the kernel select
// a valid port at bind time), that will result in two possible ports being provided back from the resultant endpoint
// initializations. Since IPv6 is POR for Matter, let's go ahead and pick that port.
//
app::DnssdServer::Instance().SetSecuredPort(mTransports.GetTransport().GetImplAtIndex<0>().GetBoundPort());
app::DnssdServer::Instance().SetUnsecuredPort(mUserDirectedCommissioningPort);
app::DnssdServer::Instance().SetInterfaceId(mInterfaceId);
#if CHIP_CONFIG_ENABLE_ICD_SERVER
// We set the ICDManager reference betfore calling the ICDManager init due to the init ordering limitations.
// DnssdServer will use the default value initially and will update advertisement once ICDManager
// init is called.
app::DnssdServer::Instance().SetICDManager(&mICDManager);
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
if (GetFabricTable().FabricCount() != 0)
{
// The device is already commissioned, proactively disable BLE advertisement.
ChipLogProgress(AppServer, "Fabric already commissioned. Disabling BLE advertisement");
#if CONFIG_NETWORK_LAYER_BLE
chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(false);
#endif
}
else
{
#if CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART
SuccessOrExit(err = mCommissioningWindowManager.OpenBasicCommissioningWindow());
#endif
}
// TODO @bzbarsky-apple @cecille Move to examples
// ESP32 and Mbed OS examples have a custom logic for enabling DNS-SD
#if !CHIP_DEVICE_LAYER_TARGET_ESP32 && !CHIP_DEVICE_LAYER_TARGET_MBED && \
(!CHIP_DEVICE_LAYER_TARGET_AMEBA || !CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE)
// StartServer only enables commissioning mode if device has not been commissioned
app::DnssdServer::Instance().StartServer();
#endif
caseSessionManagerConfig = {
.sessionInitParams = {
.sessionManager = &mSessions,
.sessionResumptionStorage = mSessionResumptionStorage,
.certificateValidityPolicy = &mCertificateValidityPolicy,
.exchangeMgr = &mExchangeMgr,
.fabricTable = &mFabrics,
.groupDataProvider = mGroupsProvider,
// Don't provide an MRP local config, so each CASE initiation will use
// the then-current value.
.mrpLocalConfig = NullOptional,
},
.clientPool = &mCASEClientPool,
.sessionSetupPool = &mSessionSetupPool,
};
err = mCASESessionManager.Init(&DeviceLayer::SystemLayer(), caseSessionManagerConfig);
SuccessOrExit(err);
err = mCASEServer.ListenForSessionEstablishment(&mExchangeMgr, &mSessions, &mFabrics, mSessionResumptionStorage,
&mCertificateValidityPolicy, mGroupsProvider);
SuccessOrExit(err);
err = chip::app::InteractionModelEngine::GetInstance()->Init(&mExchangeMgr, &GetFabricTable(), mReportScheduler,
&mCASESessionManager, mSubscriptionResumptionStorage);
SuccessOrExit(err);
#if CHIP_CONFIG_ENABLE_ICD_SERVER
app::InteractionModelEngine::GetInstance()->SetICDManager(&mICDManager);
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
// ICD Init needs to be after data model init and InteractionModel Init
#if CHIP_CONFIG_ENABLE_ICD_SERVER
// Register the ICDStateObservers.
// Call register before init so that observers are notified of any state change during the init.
// All observers are released at mICDManager.Shutdown(). They can be released individually with ReleaseObserver
mICDManager.RegisterObserver(mReportScheduler);
mICDManager.RegisterObserver(&app::DnssdServer::Instance());
#if CHIP_CONFIG_ENABLE_ICD_CIP
mICDManager.SetPersistentStorageDelegate(mDeviceStorage)
.SetFabricTable(&GetFabricTable())
.SetSymmetricKeyStore(mSessionKeystore)
.SetExchangeManager(&mExchangeMgr)
.SetSubscriptionsInfoProvider(chip::app::InteractionModelEngine::GetInstance())
.SetICDCheckInBackOffStrategy(initParams.icdCheckInBackOffStrategy);
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
mICDManager.Init();
// Register Test Event Trigger Handler
if (mTestEventTriggerDelegate != nullptr)
{
mTestEventTriggerDelegate->AddHandler(&mICDManager);
}
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
// This code is necessary to restart listening to existing groups after a reboot
// Each manufacturer needs to validate that they can rejoin groups by placing this code at the appropriate location for them
//
// Thread LWIP devices using dedicated Inet endpoint implementations are excluded because they call this function from:
// src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread_LwIP.cpp
#if !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
RejoinExistingMulticastGroups();
#endif // !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
// Handle deferred clean-up of a previously armed fail-safe that occurred during FabricTable commit.
// This is done at the very end since at the earlier time above when FabricTable::Init() is called,
// the delegates could not have been registered, and the other systems were not initialized. By now,
// everything is initialized, so we can do a deferred clean-up.
{
FabricIndex fabricIndexDeletedOnInit = GetFabricTable().GetDeletedFabricFromCommitMarker();
if (fabricIndexDeletedOnInit != kUndefinedFabricIndex)
{
ChipLogError(AppServer, "FabricIndex 0x%x deleted due to restart while fail-safed. Processing a clean-up!",
static_cast<unsigned>(fabricIndexDeletedOnInit));
// Always pretend it was an add, since being in the middle of an update currently breaks
// the validity of the fabric table. This is expected to be extremely infrequent, so
// this "harsher" than usual clean-up is more likely to get us in a valid state for whatever
// remains.
const bool addNocCalled = true;
const bool updateNocCalled = false;
GetFailSafeContext().ScheduleFailSafeCleanup(fabricIndexDeletedOnInit, addNocCalled, updateNocCalled);
// Schedule clearing of the commit marker to only occur after we have processed all fail-safe clean-up.
// Because Matter runs a single event loop for all scheduled work, it will occur after the above has
// taken place. If a reset occurs before we have cleaned everything up, the next boot will still
// see the commit marker.
PlatformMgr().ScheduleWork(
[](intptr_t arg) {
Server * server = reinterpret_cast<Server *>(arg);
VerifyOrReturn(server != nullptr);
server->GetFabricTable().ClearCommitMarker();
ChipLogProgress(AppServer, "Cleared FabricTable pending commit marker");
},
reinterpret_cast<intptr_t>(this));
}
}
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT // support UDC port for commissioner declaration msgs
mUdcTransportMgr = chip::Platform::New<UdcTransportMgr>();
ReturnErrorOnFailure(mUdcTransportMgr->Init(Transport::UdpListenParameters(DeviceLayer::UDPEndPointManager())
.SetAddressType(Inet::IPAddressType::kIPv6)
.SetListenPort(static_cast<uint16_t>(mCdcListenPort))
#if INET_CONFIG_ENABLE_IPV4
,
Transport::UdpListenParameters(DeviceLayer::UDPEndPointManager())
.SetAddressType(Inet::IPAddressType::kIPv4)
.SetListenPort(static_cast<uint16_t>(mCdcListenPort))
#endif // INET_CONFIG_ENABLE_IPV4
));
gUDCClient = chip::Platform::New<Protocols::UserDirectedCommissioning::UserDirectedCommissioningClient>();
mUdcTransportMgr->SetSessionManager(gUDCClient);
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
PlatformMgr().AddEventHandler(OnPlatformEventWrapper, reinterpret_cast<intptr_t>(this));
PlatformMgr().HandleServerStarted();
mIsDnssdReady = Dnssd::Resolver::Instance().IsInitialized();
CheckServerReadyEvent();
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "ERROR setting up transport: %" CHIP_ERROR_FORMAT, err.Format());
}
else
{
// NOTE: this log is scraped by the test harness.
ChipLogProgress(AppServer, "Server Listening...");
}
return err;
}
void Server::OnPlatformEvent(const DeviceLayer::ChipDeviceEvent & event)
{
switch (event.Type)
{
case DeviceEventType::kDnssdInitialized:
// Platform DNS-SD implementation uses kPlatformDnssdInitialized event to signal that it's ready.
if (!mIsDnssdReady)
{
mIsDnssdReady = true;
CheckServerReadyEvent();
}
break;
case DeviceEventType::kServerReady:
#if CHIP_CONFIG_ENABLE_ICD_SERVER && CHIP_CONFIG_ENABLE_ICD_CIP
// Only Trigger Check-In messages if we are not in the middle of a commissioning.
// This check is only necessary for the first commissioiner since the kServerReady event
// is triggered once we join the network.
// We trigger Check-In messages before resuming subscriptions to avoid doing both.
if (!mFailSafeContext.IsFailSafeArmed())
{
std::function<app::ICDManager::ShouldCheckInMsgsBeSentFunction> sendCheckInMessagesOnBootUp =
std::bind(&Server::ShouldCheckInMsgsBeSentAtBootFunction, this, std::placeholders::_1, std::placeholders::_2);
mICDManager.TriggerCheckInMessages(sendCheckInMessagesOnBootUp);
}
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && CHIP_CONFIG_ENABLE_ICD_CIP
#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
ResumeSubscriptions();
#endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
break;
#if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
case DeviceEventType::kThreadConnectivityChange:
if (event.ThreadConnectivityChange.Result == kConnectivity_Established)
{
// Refresh Multicast listening
ChipLogDetail(DeviceLayer, "Thread Attached updating Multicast address");
RejoinExistingMulticastGroups();
}
break;
#endif // CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
default:
break;
}
}
void Server::CheckServerReadyEvent()
{
// Check if all asynchronously initialized server components (currently, only DNS-SD)
// are ready, and emit the 'server ready' event if so.
if (mIsDnssdReady)
{
ChipLogProgress(AppServer, "Server initialization complete");
ChipDeviceEvent event = { .Type = DeviceEventType::kServerReady };
PlatformMgr().PostEventOrDie(&event);
}
}
void Server::OnPlatformEventWrapper(const DeviceLayer::ChipDeviceEvent * event, intptr_t server)
{
reinterpret_cast<Server *>(server)->OnPlatformEvent(*event);
}
void Server::RejoinExistingMulticastGroups()
{
ChipLogProgress(AppServer, "Joining Multicast groups");
CHIP_ERROR err = CHIP_NO_ERROR;
for (const FabricInfo & fabric : mFabrics)
{
Credentials::GroupDataProvider::GroupInfo groupInfo;
auto * iterator = mGroupsProvider->IterateGroupInfo(fabric.GetFabricIndex());
if (iterator)
{
// GroupDataProvider was able to allocate rescources for an iterator
while (iterator->Next(groupInfo))
{
err = mTransports.MulticastGroupJoinLeave(
Transport::PeerAddress::Multicast(fabric.GetFabricId(), groupInfo.group_id), true);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Error when trying to join Group %u of fabric index %u : %" CHIP_ERROR_FORMAT,
groupInfo.group_id, fabric.GetFabricIndex(), err.Format());
// We assume the failure is caused by a network issue or a lack of rescources; neither of which will be solved
// before the next join. Exit the loop to save rescources.
iterator->Release();
return;
}
}
iterator->Release();
}
}
}
#if CHIP_CONFIG_ENABLE_ICD_CIP
bool Server::ShouldCheckInMsgsBeSentAtBootFunction(FabricIndex aFabricIndex, NodeId subjectID)
{
#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
// If at least one registration has a persisted entry, do not send Check-In message.
// The resumption of the persisted subscription will serve the same function a check-in would have served.
return !app::InteractionModelEngine::GetInstance()->SubjectHasPersistedSubscription(aFabricIndex, subjectID);
#else
return true;
#endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
}
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
void Server::GenerateShutDownEvent()
{
PlatformMgr().ScheduleWork([](intptr_t) { PlatformMgr().HandleServerShuttingDown(); });
}
void Server::ScheduleFactoryReset()
{
PlatformMgr().ScheduleWork([](intptr_t) {
// Delete all fabrics and emit Leave event.
GetInstance().GetFabricTable().DeleteAllFabrics();
PlatformMgr().HandleServerShuttingDown();
ConfigurationMgr().InitiateFactoryReset();
});
}
void Server::Shutdown()
{
assertChipStackLockedByCurrentThread();
PlatformMgr().RemoveEventHandler(OnPlatformEventWrapper, 0);
mCASEServer.Shutdown();
mCASESessionManager.Shutdown();
#if CHIP_CONFIG_ENABLE_ICD_SERVER
app::DnssdServer::Instance().SetICDManager(nullptr);
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
app::DnssdServer::Instance().SetCommissioningModeProvider(nullptr);
chip::Dnssd::ServiceAdvertiser::Instance().Shutdown();
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
if (mUdcTransportMgr != nullptr)
{
chip::Platform::Delete(mUdcTransportMgr);
mUdcTransportMgr = nullptr;
}
if (gUDCClient != nullptr)
{
chip::Platform::Delete(gUDCClient);
gUDCClient = nullptr;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
chip::Dnssd::Resolver::Instance().Shutdown();
chip::app::InteractionModelEngine::GetInstance()->Shutdown();
#if CHIP_CONFIG_ENABLE_ICD_SERVER
app::InteractionModelEngine::GetInstance()->SetICDManager(nullptr);
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
// Shut down any remaining sessions (and hence exchanges) before we do any
// futher teardown. CASE handshakes have been shut down already via
// shutting down mCASESessionManager and mCASEServer above; shutting
// down mCommissioningWindowManager will shut down any PASE handshakes we
// have going on.
mSessions.ExpireAllSecureSessions();
mCommissioningWindowManager.Shutdown();
mMessageCounterManager.Shutdown();
mExchangeMgr.Shutdown();
mSessions.Shutdown();
mTransports.Close();
mAccessControl.Finish();
Access::ResetAccessControlToDefault();
Credentials::SetGroupDataProvider(nullptr);
#if CHIP_CONFIG_ENABLE_ICD_SERVER
// Remove Test Event Trigger Handler
if (mTestEventTriggerDelegate != nullptr)
{
mTestEventTriggerDelegate->RemoveHandler(&mICDManager);
}
mICDManager.Shutdown();
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
mAttributePersister.Shutdown();
// TODO(16969): Remove chip::Platform::MemoryInit() call from Server class, it belongs to outer code
chip::Platform::MemoryShutdown();
}
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
// NOTE: UDC client is located in Server.cpp because it really only makes sense
// to send UDC from a Matter device. The UDC message payload needs to include the device's
// randomly generated service name.
CHIP_ERROR Server::SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress commissioner,
Protocols::UserDirectedCommissioning::IdentificationDeclaration & id)
{
ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest()");
CHIP_ERROR err;
// only populate fields left blank by the client
if (strlen(id.GetInstanceName()) == 0)
{
ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Instance Name not known");
char nameBuffer[chip::Dnssd::Commission::kInstanceNameMaxLength + 1];
err = app::DnssdServer::Instance().GetCommissionableInstanceName(nameBuffer, sizeof(nameBuffer));
if (err != CHIP_NO_ERROR)
{
ChipLogError(
AppServer,
"Server::SendUserDirectedCommissioningRequest() Failed to get mdns instance name error: %" CHIP_ERROR_FORMAT,
err.Format());
return err;
}
id.SetInstanceName(nameBuffer);
ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Instance Name set to %s", nameBuffer);
}
if (id.GetVendorId() == 0)
{
uint16_t vendorId = 0;
if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(vendorId) != CHIP_NO_ERROR)
{
ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Vendor ID not known");
}
else
{
id.SetVendorId(vendorId);
}
}
if (id.GetProductId() == 0)
{
uint16_t productId = 0;
if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetProductId(productId) != CHIP_NO_ERROR)
{
ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Product ID not known");
}
else
{
id.SetProductId(productId);
}
}
if (strlen(id.GetDeviceName()) == 0)
{
char deviceName[chip::Dnssd::kKeyDeviceNameMaxLength + 1] = {};
if (!chip::DeviceLayer::ConfigurationMgr().IsCommissionableDeviceNameEnabled() ||
chip::DeviceLayer::ConfigurationMgr().GetCommissionableDeviceName(deviceName, sizeof(deviceName)) != CHIP_NO_ERROR)
{
ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Device Name not known");
}
else
{
id.SetDeviceName(deviceName);
}
}
#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID)
if (id.GetRotatingIdLength() == 0)
{
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
uint8_t rotatingDeviceIdUniqueId[chip::DeviceLayer::ConfigurationManager::kRotatingDeviceIDUniqueIDLength];
MutableByteSpan rotatingDeviceIdUniqueIdSpan(rotatingDeviceIdUniqueId);
ReturnErrorOnFailure(
chip::DeviceLayer::GetDeviceInstanceInfoProvider()->GetRotatingDeviceIdUniqueId(rotatingDeviceIdUniqueIdSpan));
ReturnErrorOnFailure(
chip::DeviceLayer::ConfigurationMgr().GetLifetimeCounter(additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter));
additionalDataPayloadParams.rotatingDeviceIdUniqueId = rotatingDeviceIdUniqueIdSpan;
uint8_t rotatingDeviceIdInternalBuffer[RotatingDeviceId::kMaxLength];
MutableByteSpan rotatingDeviceIdBufferTemp(rotatingDeviceIdInternalBuffer);
ReturnErrorOnFailure(AdditionalDataPayloadGenerator().generateRotatingDeviceIdAsBinary(additionalDataPayloadParams,
rotatingDeviceIdBufferTemp));
id.SetRotatingId(rotatingDeviceIdInternalBuffer, RotatingDeviceId::kMaxLength);
}
#endif
if (id.GetCdPort() == 0)
{
id.SetCdPort(mCdcListenPort);
}
err = gUDCClient->SendUDCMessage(&mTransports, id, commissioner);
if (err == CHIP_NO_ERROR)
{
ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Send UDC request success");
}
else
{
ChipLogError(AppServer, "Server::SendUserDirectedCommissioningRequest() Send UDC request failed, err: %" CHIP_ERROR_FORMAT,
err.Format());
}
return err;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
void Server::ResumeSubscriptions()
{
CHIP_ERROR err = chip::app::InteractionModelEngine::GetInstance()->ResumeSubscriptions();
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Error when trying to resume subscriptions : %" CHIP_ERROR_FORMAT, err.Format());
}
}
#endif
Credentials::IgnoreCertificateValidityPeriodPolicy Server::sDefaultCertValidityPolicy;
KvsPersistentStorageDelegate CommonCaseDeviceServerInitParams::sKvsPersistenStorageDelegate;
PersistentStorageOperationalKeystore CommonCaseDeviceServerInitParams::sPersistentStorageOperationalKeystore;
Credentials::PersistentStorageOpCertStore CommonCaseDeviceServerInitParams::sPersistentStorageOpCertStore;
Credentials::GroupDataProviderImpl CommonCaseDeviceServerInitParams::sGroupDataProvider;
app::DefaultTimerDelegate CommonCaseDeviceServerInitParams::sTimerDelegate;
app::reporting::ReportSchedulerImpl
CommonCaseDeviceServerInitParams::sReportScheduler(&CommonCaseDeviceServerInitParams::sTimerDelegate);
#if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION
SimpleSessionResumptionStorage CommonCaseDeviceServerInitParams::sSessionResumptionStorage;
#endif
#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
app::SimpleSubscriptionResumptionStorage CommonCaseDeviceServerInitParams::sSubscriptionResumptionStorage;
#endif
app::DefaultAclStorage CommonCaseDeviceServerInitParams::sAclStorage;
Crypto::DefaultSessionKeystore CommonCaseDeviceServerInitParams::sSessionKeystore;
#if CHIP_CONFIG_ENABLE_ICD_CIP
app::DefaultICDCheckInBackOffStrategy CommonCaseDeviceServerInitParams::sDefaultICDCheckInBackOffStrategy;
#endif
} // namespace chip