| /* |
| * |
| * 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/EventManagement.h> |
| #include <app/InteractionModelEngine.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 { |
| |
| class DeviceTypeResolver : public chip::Access::AccessControl::DeviceTypeResolver |
| { |
| public: |
| bool IsDeviceTypeOnEndpoint(chip::DeviceTypeId deviceType, chip::EndpointId endpoint) override |
| { |
| return chip::app::IsDeviceTypeOnEndpoint(deviceType, endpoint); |
| } |
| } sDeviceTypeResolver; |
| |
| } // 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 |