Skip to content

Commit

Permalink
Add Darwin API for starting multiple controllers on the same fabric.
Browse files Browse the repository at this point in the history
  • Loading branch information
bzbarsky-apple committed Aug 2, 2023
1 parent 0d81aa5 commit 4923b71
Show file tree
Hide file tree
Showing 7 changed files with 353 additions and 66 deletions.
1 change: 1 addition & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams
// bring-up.
commissionerParams.removeFromFabricTableOnShutdown = false;
commissionerParams.deviceAttestationVerifier = _factory.deviceAttestationVerifier;
commissionerParams.permitMultiControllerFabrics = startupParams.isAdditionalController;

auto & factory = chip::Controller::DeviceControllerFactory::GetInstance();

Expand Down
16 changes: 16 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,22 @@ API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
- (MTRDeviceController * _Nullable)createControllerOnExistingFabric:(MTRDeviceControllerStartupParams *)startupParams
error:(NSError * __autoreleasing *)error;

/**
* Create an additional MTRDeviceController on an existing fabric. Returns nil on failure.
*
* The fabric is identified by the root public key and fabric id in
* the startupParams.
*
* This method will fail if there is no such fabric.
*
* This method will fail if the MTRDeviceControllerStartupParams don't follow
* the rules for creating a controller on a new fabric. In particular, the
* vendor ID must not be nil.
*/
- (MTRDeviceController * _Nullable)createAdditionalControllerOnExistingFabric:(MTRDeviceControllerStartupParams *)startupParams
error:(NSError * __autoreleasing *)error
MTR_NEWLY_AVAILABLE;

/**
* Create a MTRDeviceController on a new fabric. Returns nil on failure.
*
Expand Down
86 changes: 47 additions & 39 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,21 @@ - (MTRDeviceController * _Nullable)_startDeviceController:(MTRDeviceControllerSt
return controller;
}

- (MTRDeviceController * _Nullable)createAdditionalControllerOnExistingFabric:(MTRDeviceControllerStartupParams *)startupParams
error:(NSError * __autoreleasing *)error
{
return [self _createControllerOnExistingFabric:startupParams isAdditional:YES error:error];
}

- (MTRDeviceController * _Nullable)createControllerOnExistingFabric:(MTRDeviceControllerStartupParams *)startupParams
error:(NSError * __autoreleasing *)error
{
return [self _createControllerOnExistingFabric:startupParams isAdditional:NO error:error];
}

- (MTRDeviceController * _Nullable)_createControllerOnExistingFabric:(MTRDeviceControllerStartupParams *)startupParams
isAdditional:(BOOL)isAdditional
error:(NSError * __autoreleasing *)error
{
[self _assertCurrentQueueIsNotMatterQueue];

Expand All @@ -643,28 +656,37 @@ - (MTRDeviceController * _Nullable)createControllerOnExistingFabric:(MTRDeviceCo

auto * controllersCopy = [self getRunningControllers];

for (MTRDeviceController * existing in controllersCopy) {
BOOL isRunning = YES; // assume the worst
if ([existing isRunningOnFabric:fabricTable fabricIndex:fabric->GetFabricIndex() isRunning:&isRunning]
!= CHIP_NO_ERROR) {
MTR_LOG_ERROR("Can't tell what fabric a controller is running on. Not safe to start.");
fabricError = CHIP_ERROR_INTERNAL;
return nil;
MTRDeviceControllerStartupParamsInternal * params;
if (!isAdditional) {
for (MTRDeviceController * existing in controllersCopy) {
BOOL isRunning = YES; // assume the worst
if ([existing isRunningOnFabric:fabricTable fabricIndex:fabric->GetFabricIndex() isRunning:&isRunning]
!= CHIP_NO_ERROR) {
MTR_LOG_ERROR("Can't tell what fabric a controller is running on. Not safe to start.");
fabricError = CHIP_ERROR_INTERNAL;
return nil;
}

if (isRunning) {
MTR_LOG_ERROR("Can't start on existing fabric: another controller is running on it");
fabricError = CHIP_ERROR_INCORRECT_STATE;
return nil;
}
}

if (isRunning) {
MTR_LOG_ERROR("Can't start on existing fabric: another controller is running on it");
fabricError = CHIP_ERROR_INCORRECT_STATE;
return nil;
}
params =
[[MTRDeviceControllerStartupParamsInternal alloc] _initForExistingFabricEntry:fabricTable
fabricIndex:fabric->GetFabricIndex()
keystore:self->_keystore
advertiseOperational:self.advertiseOperational
params:startupParams];
} else {
params = [[MTRDeviceControllerStartupParamsInternal alloc] _initForNewFabricEntry:fabricTable
keystore:self->_keystore
advertiseOperational:self.advertiseOperational
params:startupParams
isAdditionalController:YES];
}

auto * params =
[[MTRDeviceControllerStartupParamsInternal alloc] initForExistingFabric:fabricTable
fabricIndex:fabric->GetFabricIndex()
keystore:self->_keystore
advertiseOperational:self.advertiseOperational
params:startupParams];
if (params == nil) {
fabricError = CHIP_ERROR_NO_MEMORY;
}
Expand All @@ -679,22 +701,6 @@ - (MTRDeviceController * _Nullable)createControllerOnNewFabric:(MTRDeviceControl
{
[self _assertCurrentQueueIsNotMatterQueue];

if (startupParams.vendorID == nil) {
MTR_LOG_ERROR("Must provide vendor id when starting controller on new fabric");
if (error != nil) {
*error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT];
}
return nil;
}

if (startupParams.intermediateCertificate != nil && startupParams.rootCertificate == nil) {
MTR_LOG_ERROR("Must provide a root certificate when using an intermediate certificate");
if (error != nil) {
*error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT];
}
return nil;
}

return [self
_startDeviceController:startupParams
fabricChecker:^MTRDeviceControllerStartupParamsInternal *(FabricTable * fabricTable, CHIP_ERROR & fabricError) {
Expand All @@ -712,10 +718,12 @@ - (MTRDeviceController * _Nullable)createControllerOnNewFabric:(MTRDeviceControl
return nil;
}

auto * params = [[MTRDeviceControllerStartupParamsInternal alloc] initForNewFabric:fabricTable
keystore:self->_keystore
advertiseOperational:self.advertiseOperational
params:startupParams];
auto * params =
[[MTRDeviceControllerStartupParamsInternal alloc] _initForNewFabricEntry:fabricTable
keystore:self->_keystore
advertiseOperational:self.advertiseOperational
params:startupParams
isAdditionalController:NO];
if (params == nil) {
fabricError = CHIP_ERROR_NO_MEMORY;
}
Expand Down
31 changes: 22 additions & 9 deletions src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.mm
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,26 @@ - (instancetype)initWithParams:(MTRDeviceControllerStartupParams *)params
return self;
}

- (instancetype)initForNewFabric:(chip::FabricTable *)fabricTable
keystore:(chip::Crypto::OperationalKeystore *)keystore
advertiseOperational:(BOOL)advertiseOperational
params:(MTRDeviceControllerStartupParams *)params
- (instancetype)_initForNewFabricEntry:(chip::FabricTable *)fabricTable
keystore:(chip::Crypto::OperationalKeystore *)keystore
advertiseOperational:(BOOL)advertiseOperational
params:(MTRDeviceControllerStartupParams *)params
isAdditionalController:(BOOL)isAdditionalController
{
if (!(self = [self initWithParams:params])) {
return nil;
}

if (self.vendorID == nil) {
MTR_LOG_ERROR("Must provide vendor id when starting controller on new fabric");
return nil;
}

if (self.intermediateCertificate != nil && self.rootCertificate == nil) {
MTR_LOG_ERROR("Must provide a root certificate when using an intermediate certificate");
return nil;
}

if (self.nocSigner == nil && self.operationalCertificate == nil) {
MTR_LOG_ERROR("No way to get an operational certificate: nocSigner and operationalCertificate are both nil");
return nil;
Expand Down Expand Up @@ -248,15 +259,16 @@ - (instancetype)initForNewFabric:(chip::FabricTable *)fabricTable
_fabricTable = fabricTable;
_keystore = keystore;
_advertiseOperational = advertiseOperational;
_isAdditionalController = isAdditionalController;

return self;
}

- (instancetype)initForExistingFabric:(FabricTable *)fabricTable
fabricIndex:(FabricIndex)fabricIndex
keystore:(chip::Crypto::OperationalKeystore *)keystore
advertiseOperational:(BOOL)advertiseOperational
params:(MTRDeviceControllerStartupParams *)params
- (instancetype)_initForExistingFabricEntry:(FabricTable *)fabricTable
fabricIndex:(FabricIndex)fabricIndex
keystore:(chip::Crypto::OperationalKeystore *)keystore
advertiseOperational:(BOOL)advertiseOperational
params:(MTRDeviceControllerStartupParams *)params
{
if (!(self = [self initWithParams:params])) {
return nil;
Expand Down Expand Up @@ -384,6 +396,7 @@ - (instancetype)initForExistingFabric:(FabricTable *)fabricTable
_fabricIndex.Emplace(fabricIndex);
_keystore = keystore;
_advertiseOperational = advertiseOperational;
_isAdditionalController = NO;

return self;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ MTR_HIDDEN

@property (nonatomic, assign, readonly) BOOL advertiseOperational;

@property (nonatomic, assign, readonly) BOOL isAdditionalController;

/**
* Helper method that checks that our keypairs match our certificates.
* Specifically:
Expand All @@ -73,21 +75,24 @@ MTR_HIDDEN
- (BOOL)keypairsMatchCertificates;

/**
* Initialize for controller bringup on a new fabric.
* Initialize for controller bringup on a new fabric entry (which might be a new
* fabric or an additional controller on an existing fabric).
*/
- (instancetype)initForNewFabric:(chip::FabricTable *)fabricTable
keystore:(chip::Crypto::OperationalKeystore *)keystore
advertiseOperational:(BOOL)advertiseOperational
params:(MTRDeviceControllerStartupParams *)params;
- (instancetype)_initForNewFabricEntry:(chip::FabricTable *)fabricTable
keystore:(chip::Crypto::OperationalKeystore *)keystore
advertiseOperational:(BOOL)advertiseOperational
params:(MTRDeviceControllerStartupParams *)params
isAdditionalController:(BOOL)isAdditionalController;

/**
* Initialize for controller bringup on an existing fabric.
* Initialize for controller bringup on an existing fabric entry, identified by
* the provided fabricIndex.
*/
- (instancetype)initForExistingFabric:(chip::FabricTable *)fabricTable
fabricIndex:(chip::FabricIndex)fabricIndex
keystore:(chip::Crypto::OperationalKeystore *)keystore
advertiseOperational:(BOOL)advertiseOperational
params:(MTRDeviceControllerStartupParams *)params;
- (instancetype)_initForExistingFabricEntry:(chip::FabricTable *)fabricTable
fabricIndex:(chip::FabricIndex)fabricIndex
keystore:(chip::Crypto::OperationalKeystore *)keystore
advertiseOperational:(BOOL)advertiseOperational
params:(MTRDeviceControllerStartupParams *)params;

/**
* Should use initForExistingFabric or initForNewFabric to initialize
Expand Down
Loading

0 comments on commit 4923b71

Please sign in to comment.