Skip to content

Commit

Permalink
[Matter.framework] Add MTRDiagnosticLogsDelegate to the Matter.framework
Browse files Browse the repository at this point in the history
  • Loading branch information
vivien-apple committed Dec 28, 2023
1 parent bae1085 commit 6c5a1f0
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

NS_ASSUME_NONNULL_BEGIN

@protocol MTRDiagnosticLogsDelegate;
@protocol MTRStorage;
@protocol MTRPersistentStorageDelegate;
@protocol MTROTAProviderDelegate;
Expand Down Expand Up @@ -58,6 +59,14 @@ MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
*/
@property (nonatomic, strong, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;

/*
* Diagnostic Logs delegate to be called when a BDX transfer request for logs is received.
*
* Calls to this delegate can happen on an arbitrary thread, but will not happen
* concurrently.
*/
@property (nonatomic, strong, nullable) id<MTRDiagnosticLogsDelegate> diagnosticLogsDelegate;

/*
* The Product Attestation Authority certificates that are trusted to sign
* device attestation information (and in particular to sign Product Attestation
Expand Down
44 changes: 44 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#import "MTRDeviceControllerStartupParams.h"
#import "MTRDeviceControllerStartupParams_Internal.h"
#import "MTRDeviceController_Internal.h"
#import "MTRDiagnosticLogsDelegateBridge.h"
#import "MTRError_Internal.h"
#import "MTRFabricInfo_Internal.h"
#import "MTRFramework.h"
Expand Down Expand Up @@ -80,6 +81,7 @@ @interface MTRDeviceControllerFactory ()
@property (readonly) DeviceControllerFactory * controllerFactory;
@property (readonly) PersistentStorageDelegate * persistentStorageDelegate;
@property (readonly) MTROTAProviderDelegateBridge * otaProviderDelegateBridge;
@property (readonly) MTRDiagnosticLogsDelegateBridge * diagnosticLogsDelegateBridge;
@property (readonly) Crypto::RawKeySessionKeystore * sessionKeystore;
// We use TestPersistentStorageDelegate just to get an in-memory store to back
// our group data provider impl. We initialize this store correctly on every
Expand Down Expand Up @@ -133,11 +135,14 @@ @interface MTRDeviceControllerFactory ()
@property (nonatomic, readonly, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;
@property (nonatomic, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue;

@property (nonatomic, readonly, nullable) id<MTRDiagnosticLogsDelegate> diagnosticLogsDelegate;

- (BOOL)findMatchingFabric:(FabricTable &)fabricTable
params:(MTRDeviceControllerStartupParams *)params
fabric:(const FabricInfo * _Nullable * _Nonnull)fabric;

- (MTRDeviceController * _Nullable)maybeInitializeOTAProvider:(MTRDeviceController * _Nonnull)controller;
- (MTRDeviceController * _Nullable)maybeInitializeDiagnosticLogsDelegate:(MTRDeviceController * _Nonnull)controller;
@end

@interface MTRDeviceControllerFactoryParams ()
Expand Down Expand Up @@ -323,6 +328,12 @@ - (void)cleanupStartupObjects
_otaProviderDelegateQueue = nil;
_otaProviderDelegate = nil;

if (_diagnosticLogsDelegateBridge) {
delete _diagnosticLogsDelegateBridge;
_diagnosticLogsDelegateBridge = nullptr;
}
_diagnosticLogsDelegate = nil;

if (_sessionResumptionStorage) {
delete _sessionResumptionStorage;
_sessionResumptionStorage = nullptr;
Expand Down Expand Up @@ -436,6 +447,10 @@ - (BOOL)startControllerFactory:(MTRDeviceControllerFactoryParams *)startupParams
}
_otaProviderDelegateBridge = new MTROTAProviderDelegateBridge();

_diagnosticLogsDelegateBridge = new MTRDiagnosticLogsDelegateBridge();
_diagnosticLogsDelegate = startupParams.diagnosticLogsDelegate;
_diagnosticLogsDelegateBridge->SetDelegate(_diagnosticLogsDelegate);

// TODO: Allow passing a different keystore implementation via startupParams.
_keystore = new PersistentStorageOperationalKeystore();
if (_keystore == nullptr) {
Expand Down Expand Up @@ -722,6 +737,13 @@ - (MTRDeviceController * _Nullable)_startDeviceController:(MTRDeviceController *
*error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INTERNAL];
}
}

controller = [self maybeInitializeDiagnosticLogsDelegate:controller];
if (controller == nil) {
if (error != nil) {
*error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INTERNAL];
}
}
return controller;
}

Expand Down Expand Up @@ -912,6 +934,26 @@ - (MTRDeviceController * _Nullable)maybeInitializeOTAProvider:(MTRDeviceControll
return controller;
}

// Initialize the MTRDiagnosticLogsDelegateBridge if it has not been initialized already
//
// Returns nil on failure, the input controller on success.
// If the delegate has been initialized already, it is not considered as a failure.
//
- (MTRDeviceController * _Nullable)maybeInitializeDiagnosticLogsDelegate:(MTRDeviceController * _Nonnull)controller
{
[self _assertCurrentQueueIsNotMatterQueue];

VerifyOrReturnValue(_diagnosticLogsDelegateBridge != nil, controller);
VerifyOrReturnValue([_controllers count] == 1, controller);

dispatch_sync(_chipWorkQueue, ^{
auto systemState = _controllerFactory->GetSystemState();
systemState->BDXTransferServer()->SetDelegate(_diagnosticLogsDelegateBridge);
});

return controller;
}

@end

@implementation MTRDeviceControllerFactory (InternalMethods)
Expand Down Expand Up @@ -1158,6 +1200,7 @@ - (instancetype)initWithStorage:(id<MTRStorage>)storage
_storage = storage;
_hasStorage = YES;
_otaProviderDelegate = nil;
_diagnosticLogsDelegate = nil;
_productAttestationAuthorityCertificates = nil;
_certificationDeclarationCertificates = nil;
_port = nil;
Expand All @@ -1178,6 +1221,7 @@ - (instancetype)initWithoutStorage
_storage = [[MTRDummyStorage alloc] init];
_hasStorage = NO;
_otaProviderDelegate = nil;
_diagnosticLogsDelegate = nil;
_productAttestationAuthorityCertificates = nil;
_certificationDeclarationCertificates = nil;
_port = nil;
Expand Down
73 changes: 73 additions & 0 deletions src/darwin/Framework/CHIP/MTRDiagnosticLogsDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
*
* Copyright (c) 2023 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.
*/

#import <Foundation/Foundation.h>
#import <Matter/MTRCluster.h>
#import <Matter/MTRDefines.h>

@class MTRDeviceController;

NS_ASSUME_NONNULL_BEGIN

/**
* The protocol definition for the MTRDiagnosticLogsDelegate.
*
*/
@protocol MTRDiagnosticLogsDelegate <NSObject>
/**
* Notify the delegate when a BDX Session starts for some logs.
* The controller identifies the fabric the node is on, and the
* nodeID identifies the node within that fabric.
*
* If completion is passed a non-nil error, that will be converted into
* an error response to the sender. Otherwise a success response will be sent.
*/
- (void)handleBDXTransferSessionBeginForNodeID:(NSNumber *)nodeID
controller:(MTRDeviceController *)controller
fileDesignator:(NSString *)fileDesignator
completion:(MTRStatusCompletion)completion
MTR_NEWLY_AVAILABLE;

/**
* Notify the delegate when some data is received on the BDX Session.
* The controller identifies the fabric the node is on, and the
* nodeID identifies the node within that fabric.
*
* If completion is passed a non-nil error, that will be converted into
* an error response to the sender. Otherwise a success response will be sent.
*/
- (void)handleBDXTransferSessionDataForNodeID:(NSNumber *)nodeID
controller:(MTRDeviceController *)controller
fileDesignator:(NSString *)fileDesignator
data:(NSData *)data
completion:(MTRStatusCompletion)completion
MTR_NEWLY_AVAILABLE;

/**
* Notify the delegate when a BDX Session ends for some logs.
* The controller identifies the fabric the node is on, and the
* nodeID identifies the node within that fabric.
*/
- (void)handleBDXTransferSessionEndForNodeID:(NSNumber *)nodeID
controller:(MTRDeviceController *)controller
fileDesignator:(NSString *)fileDesignator
error:(NSError * _Nullable)error
MTR_NEWLY_AVAILABLE;

@end

NS_ASSUME_NONNULL_END
42 changes: 42 additions & 0 deletions src/darwin/Framework/CHIP/MTRDiagnosticLogsDelegateBridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
*
* Copyright (c) 2023 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.
*/

#import <Matter/MTRDiagnosticLogsDelegate.h>

#include <protocols/bdx/BdxTransferServerDelegate.h>

NS_ASSUME_NONNULL_BEGIN

class MTRDiagnosticLogsDelegateBridge : public chip::bdx::BDXTransferServerDelegate
{
public:
MTRDiagnosticLogsDelegateBridge();
~MTRDiagnosticLogsDelegateBridge();

void SetDelegate(id<MTRDiagnosticLogsDelegate> delegate) { mDelegate = delegate; };

/////////// BDXTransferServerDelegate Interface /////////
CHIP_ERROR OnTransferBegin(chip::bdx::BDXTransferProxy * transfer) override;
CHIP_ERROR OnTransferEnd(chip::bdx::BDXTransferProxy * transfer, CHIP_ERROR error) override;
CHIP_ERROR OnTransferData(chip::bdx::BDXTransferProxy * transfer, const chip::ByteSpan & data) override;

private:
id<MTRDiagnosticLogsDelegate> mDelegate;
dispatch_queue_t mDelegateNotificationQueue;
};

NS_ASSUME_NONNULL_END
137 changes: 137 additions & 0 deletions src/darwin/Framework/CHIP/MTRDiagnosticLogsDelegateBridge.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
*
* Copyright (c) 2023 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.
*/

#import "MTRDiagnosticLogsDelegateBridge.h"

#import "MTRDeviceControllerFactory_Internal.h"
#import "MTRDeviceController_Internal.h"
#import "MTRError_Internal.h"
#import "NSDataSpanConversion.h"
#import "NSStringSpanConversion.h"

constexpr const char kQueueName[] = "org.csa-iot.matter.framework.diagnosticlogs.workqueue";

MTRDiagnosticLogsDelegateBridge::MTRDiagnosticLogsDelegateBridge()
{
mDelegateNotificationQueue = dispatch_queue_create(kQueueName, DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
}

MTRDiagnosticLogsDelegateBridge::~MTRDiagnosticLogsDelegateBridge()
{
mDelegateNotificationQueue = nil;
mDelegate = nil;
}

CHIP_ERROR MTRDiagnosticLogsDelegateBridge::OnTransferBegin(chip::bdx::BDXTransferProxy * transfer)
{
VerifyOrReturnError(nil != mDelegate, CHIP_ERROR_NOT_IMPLEMENTED);

auto fileDesignatorSpan = transfer->GetFileDesignator();
auto fileDesignator = AsString(fileDesignatorSpan);
VerifyOrReturnError(nil != fileDesignator, CHIP_ERROR_INCORRECT_STATE);

auto nodeId = @(transfer->GetPeerNodeId());
auto fabricIndex = transfer->GetFabricIndex();
auto * controller = [[MTRDeviceControllerFactory sharedInstance] runningControllerForFabricIndex:fabricIndex];
VerifyOrReturnError(controller != nil, CHIP_ERROR_INCORRECT_STATE);

auto completionHandler = ^(NSError * _Nullable error) {
[controller asyncDispatchToMatterQueue:^() {
if (error != nil) {
auto err = [MTRError errorToCHIPErrorCode:error];
transfer->Reject(err);
} else {
transfer->Accept();
}
} errorHandler:^(NSError *) {
// Not much we can do here
}];
};

auto strongDelegate = mDelegate;
dispatch_async(
mDelegateNotificationQueue, ^{
[strongDelegate handleBDXTransferSessionBeginForNodeID:nodeId controller:controller fileDesignator:fileDesignator completion:completionHandler];
});

return CHIP_NO_ERROR;
}

CHIP_ERROR MTRDiagnosticLogsDelegateBridge::OnTransferEnd(chip::bdx::BDXTransferProxy * transfer, CHIP_ERROR error)
{
VerifyOrReturnError(nil != mDelegate, CHIP_ERROR_NOT_IMPLEMENTED);

auto fileDesignatorSpan = transfer->GetFileDesignator();
auto fileDesignator = AsString(fileDesignatorSpan);
VerifyOrReturnError(nil != fileDesignator, CHIP_ERROR_INCORRECT_STATE);

NSError * mtrError = nil;
if (CHIP_NO_ERROR != error) {
mtrError = [MTRError errorForCHIPErrorCode:error];
}

auto nodeId = @(transfer->GetPeerNodeId());
auto fabricIndex = transfer->GetFabricIndex();
auto * controller = [[MTRDeviceControllerFactory sharedInstance] runningControllerForFabricIndex:fabricIndex];
VerifyOrReturnError(controller != nil, CHIP_ERROR_INCORRECT_STATE);

auto strongDelegate = mDelegate;
dispatch_async(
mDelegateNotificationQueue, ^{
[strongDelegate handleBDXTransferSessionEndForNodeID:nodeId controller:controller fileDesignator:fileDesignator error:mtrError];
});

return CHIP_NO_ERROR;
}

CHIP_ERROR MTRDiagnosticLogsDelegateBridge::OnTransferData(chip::bdx::BDXTransferProxy * transfer, const chip::ByteSpan & dataSpan)
{
VerifyOrReturnError(nil != mDelegate, CHIP_ERROR_NOT_IMPLEMENTED);

auto fileDesignatorSpan = transfer->GetFileDesignator();
auto fileDesignator = AsString(fileDesignatorSpan);
VerifyOrReturnError(nil != fileDesignator, CHIP_ERROR_INCORRECT_STATE);

auto data = AsData(dataSpan);
VerifyOrReturnError(nil != data, CHIP_ERROR_INCORRECT_STATE);

auto nodeId = @(transfer->GetPeerNodeId());
auto fabricIndex = transfer->GetFabricIndex();
auto * controller = [[MTRDeviceControllerFactory sharedInstance] runningControllerForFabricIndex:fabricIndex];
VerifyOrReturnError(controller != nil, CHIP_ERROR_INCORRECT_STATE);

auto completionHandler = ^(NSError * _Nullable error) {
[controller asyncDispatchToMatterQueue:^() {
if (error != nil) {
auto err = [MTRError errorToCHIPErrorCode:error];
transfer->Reject(err);
} else {
transfer->Continue();
}
} errorHandler:^(NSError *) {
// Not much we can do here
}];
};

auto strongDelegate = mDelegate;
dispatch_async(
mDelegateNotificationQueue, ^{
[strongDelegate handleBDXTransferSessionDataForNodeID:nodeId controller:controller fileDesignator:fileDesignator data:data completion:completionHandler];
});

return CHIP_NO_ERROR;
}
1 change: 1 addition & 0 deletions src/darwin/Framework/CHIP/Matter.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#import <Matter/MTRDeviceControllerParameters.h>
#import <Matter/MTRDeviceControllerStartupParams.h>
#import <Matter/MTRDeviceControllerStorageDelegate.h>
#import <Matter/MTRDiagnosticLogsDelegate.h>
#import <Matter/MTRError.h>
#import <Matter/MTRFabricInfo.h>
#import <Matter/MTRKeypair.h>
Expand Down
Loading

0 comments on commit 6c5a1f0

Please sign in to comment.