26
26
#import " MTRCommissionableBrowserResult_Internal.h"
27
27
#import " MTRCommissioningParameters.h"
28
28
#import " MTRConversion.h"
29
- #import " MTRDeviceController.h"
30
29
#import " MTRDeviceControllerDelegateBridge.h"
31
30
#import " MTRDeviceControllerFactory_Internal.h"
32
31
#import " MTRDeviceControllerLocalTestStorage.h"
50
49
#import " MTRSetupPayload.h"
51
50
#import " MTRTimeUtils.h"
52
51
#import " MTRUnfairLock.h"
52
+ #import " MTRUtilities.h"
53
53
#import " NSDataSpanConversion.h"
54
54
#import " NSStringSpanConversion.h"
55
55
#import < setup_payload/ManualSetupPayloadGenerator.h>
80
80
81
81
#include < atomic>
82
82
#include < dns_sd.h>
83
+ #include < optional>
83
84
#include < string>
84
85
86
+ #import < os/lock.h>
87
+
85
88
typedef void (^SyncWorkQueueBlock)(void );
86
89
typedef id (^SyncWorkQueueBlockWithReturnValue)(void );
87
90
typedef BOOL (^SyncWorkQueueBlockWithBoolReturnValue)(void );
@@ -114,19 +117,29 @@ @interface MTRDeviceController_Concrete ()
114
117
@end
115
118
116
119
@implementation MTRDeviceController_Concrete {
117
- // queue used to serialize all work performed by the MTRDeviceController
118
120
std::atomic<chip::FabricIndex> _storedFabricIndex;
119
121
std::atomic<std::optional<uint64_t >> _storedCompressedFabricID;
120
122
MTRP256KeypairBridge _signingKeypairBridge;
121
123
MTRP256KeypairBridge _operationalKeypairBridge;
124
+
125
+ // Counters to track assertion status and access controlled by the _assertionLock
126
+ // TODO: Figure out whether they should live here or in the base class (or
127
+ // go away completely!), which depends on how the shutdown codepaths get set up.
128
+ NSUInteger _keepRunningAssertionCounter;
129
+ BOOL _shutdownPending;
130
+ os_unfair_lock _assertionLock;
122
131
}
123
132
124
- // MTRDeviceController ivar internal access
133
+ // TODO: Figure out whether uniqueIdentifier storage should live in the superclass. It
134
+ // probably should!
125
135
@synthesize uniqueIdentifier = _uniqueIdentifier;
136
+ // TODO: Figure out whether the work queue storage lives here or in the superclass
137
+ // Right now we seem to have both?
126
138
@synthesize chipWorkQueue = _chipWorkQueue;
127
139
@synthesize controllerDataStore = _controllerDataStore;
140
+ // TODO: For these remaining ivars, figure out whether they should live here or
141
+ // on the superclass. Should not be both.
128
142
@synthesize factory = _factory;
129
- @synthesize deviceMapLock = _deviceMapLock;
130
143
@synthesize otaProviderDelegate = _otaProviderDelegate;
131
144
@synthesize otaProviderDelegateQueue = _otaProviderDelegateQueue;
132
145
@synthesize commissionableBrowser = _commissionableBrowser;
@@ -165,7 +178,7 @@ - (nullable instancetype)initWithParameters:(MTRDeviceControllerAbstractParamete
165
178
MTR_LOG_DEBUG (" %s: got standard parameters, getting standard device controller from factory" , __PRETTY_FUNCTION__);
166
179
auto * controllerParameters = static_cast <MTRDeviceControllerParameters *>(parameters);
167
180
168
- // or, if necessary, MTRDeviceControllerFactory will auto-start in per-controller-storage mode if necessary
181
+ // Start us up normally. MTRDeviceControllerFactory will auto-start in per-controller-storage mode if necessary.
169
182
MTRDeviceControllerFactory * factory = MTRDeviceControllerFactory.sharedInstance ;
170
183
id controller = [factory initializeController: self
171
184
withParameters: controllerParameters
@@ -196,6 +209,12 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
196
209
// Make sure our storage is all set up to work as early as possible,
197
210
// before we start doing anything else with the controller.
198
211
_uniqueIdentifier = uniqueIdentifier;
212
+
213
+ // Setup assertion variables
214
+ _keepRunningAssertionCounter = 0 ;
215
+ _shutdownPending = NO ;
216
+ _assertionLock = OS_UNFAIR_LOCK_INIT;
217
+
199
218
if (storageDelegate != nil ) {
200
219
if (storageDelegateQueue == nil ) {
201
220
MTR_LOG_ERROR (" storageDelegate provided without storageDelegateQueue" );
@@ -269,6 +288,7 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
269
288
_otaProviderDelegateQueue = otaProviderDelegateQueue;
270
289
_chipWorkQueue = queue;
271
290
_factory = factory;
291
+ // TODO: Shouldn't nodeIDToDeviceMap just be set up by initForSubclasses?
272
292
self.nodeIDToDeviceMap = [NSMapTable strongToWeakObjectsMapTable ];
273
293
_serverEndpoints = [[NSMutableArray alloc ] init ];
274
294
_commissionableBrowser = nil ;
@@ -310,6 +330,10 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
310
330
_concurrentSubscriptionPool = [[MTRAsyncWorkQueue alloc ] initWithContext: self width: concurrentSubscriptionPoolSize];
311
331
312
332
_storedFabricIndex = chip::kUndefinedFabricIndex ;
333
+ _storedCompressedFabricID = std::nullopt;
334
+ self.nodeID = nil ;
335
+ self.fabricID = nil ;
336
+ self.rootPublicKey = nil ;
313
337
314
338
_storageBehaviorConfiguration = storageBehaviorConfiguration;
315
339
}
@@ -326,8 +350,68 @@ - (BOOL)isRunning
326
350
return _cppCommissioner != nullptr ;
327
351
}
328
352
353
+ - (BOOL )matchesPendingShutdownControllerWithOperationalCertificate : (nullable MTRCertificateDERBytes)operationalCertificate andRootCertificate : (nullable MTRCertificateDERBytes)rootCertificate
354
+ {
355
+ if (!operationalCertificate || !rootCertificate) {
356
+ return FALSE ;
357
+ }
358
+ NSNumber * nodeID = [MTRDeviceControllerParameters nodeIDFromNOC: operationalCertificate];
359
+ NSNumber * fabricID = [MTRDeviceControllerParameters fabricIDFromNOC: operationalCertificate];
360
+ NSData * publicKey = [MTRDeviceControllerParameters publicKeyFromCertificate: rootCertificate];
361
+
362
+ std::lock_guard lock (_assertionLock);
363
+
364
+ // If any of the local above are nil, the return will be false since MTREqualObjects handles them correctly
365
+ return _keepRunningAssertionCounter > 0 && _shutdownPending && MTREqualObjects (nodeID, self.nodeID ) && MTREqualObjects (fabricID, self.fabricID ) && MTREqualObjects (publicKey, self.rootPublicKey );
366
+ }
367
+
368
+ - (void )addRunAssertion
369
+ {
370
+ std::lock_guard lock (_assertionLock);
371
+
372
+ // Only take an assertion if running
373
+ if ([self isRunning ]) {
374
+ ++_keepRunningAssertionCounter;
375
+ MTR_LOG (" %@ Adding keep running assertion, total %lu" , self, static_cast <unsigned long >(_keepRunningAssertionCounter));
376
+ }
377
+ }
378
+
379
+ - (void )removeRunAssertion ;
380
+ {
381
+ std::lock_guard lock (_assertionLock);
382
+
383
+ if (_keepRunningAssertionCounter > 0 ) {
384
+ --_keepRunningAssertionCounter;
385
+ MTR_LOG (" %@ Removing keep running assertion, total %lu" , self, static_cast <unsigned long >(_keepRunningAssertionCounter));
386
+
387
+ if ([self isRunning ] && _keepRunningAssertionCounter == 0 && _shutdownPending) {
388
+ MTR_LOG (" %@ All assertions removed and shutdown is pending, shutting down" , self);
389
+ [self finalShutdown ];
390
+ }
391
+ }
392
+ }
393
+
394
+ - (void )clearPendingShutdown
395
+ {
396
+ std::lock_guard lock (_assertionLock);
397
+ _shutdownPending = NO ;
398
+ }
399
+
329
400
- (void )shutdown
330
401
{
402
+ std::lock_guard lock (_assertionLock);
403
+
404
+ if (_keepRunningAssertionCounter > 0 ) {
405
+ MTR_LOG (" %@ Pending shutdown since %lu assertions are present" , self, static_cast <unsigned long >(_keepRunningAssertionCounter));
406
+ _shutdownPending = YES ;
407
+ return ;
408
+ }
409
+ [self finalShutdown ];
410
+ }
411
+
412
+ - (void )finalShutdown
413
+ {
414
+ os_unfair_lock_assert_owner (&_assertionLock);
331
415
MTR_LOG (" %@ shutdown called" , self);
332
416
if (_cppCommissioner == nullptr ) {
333
417
// Already shut down.
@@ -383,11 +467,17 @@ - (void)shutDownCppController
383
467
// shutdown completes, in case it wants to write to storage as it
384
468
// shuts down.
385
469
_storedFabricIndex = chip::kUndefinedFabricIndex ;
470
+ _storedCompressedFabricID = std::nullopt;
471
+ self.nodeID = nil ;
472
+ self.fabricID = nil ;
473
+ self.rootPublicKey = nil ;
474
+
386
475
delete commissionerToShutDown;
387
476
if (_operationalCredentialsDelegate != nil ) {
388
477
_operationalCredentialsDelegate->SetDeviceCommissioner (nullptr );
389
478
}
390
479
}
480
+ _shutdownPending = NO ;
391
481
}
392
482
393
483
- (void )deinitFromFactory
@@ -622,6 +712,15 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams
622
712
}
623
713
624
714
self->_storedFabricIndex = fabricIdx;
715
+ self->_storedCompressedFabricID = _cppCommissioner->GetCompressedFabricId ();
716
+
717
+ chip::Crypto::P256PublicKey rootPublicKey;
718
+ if (_cppCommissioner->GetRootPublicKey (rootPublicKey) == CHIP_NO_ERROR) {
719
+ self.rootPublicKey = [NSData dataWithBytes: rootPublicKey.Bytes () length: rootPublicKey.Length ()];
720
+ self.nodeID = @(_cppCommissioner->GetNodeId ());
721
+ self.fabricID = @(_cppCommissioner->GetFabricId ());
722
+ }
723
+
625
724
commissionerInitialized = YES ;
626
725
627
726
MTR_LOG (" %@ startup succeeded for nodeID 0x%016llX" , self, self->_cppCommissioner ->GetNodeId ());
@@ -669,7 +768,7 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams
669
768
});
670
769
}];
671
770
}
672
- MTR_LOG (" %s: startup: %@" , __PRETTY_FUNCTION__ , self);
771
+ MTR_LOG (" %@ startup: %@" , NSStringFromClass (self. class ) , self);
673
772
674
773
return YES ;
675
774
}
@@ -1279,6 +1378,9 @@ - (BOOL)checkForStartError:(CHIP_ERROR)errorCode logMsg:(NSString *)logMsg
1279
1378
return YES ;
1280
1379
}
1281
1380
1381
+ // TODO: Figure out whether this should live here or in superclass; we shouldn't
1382
+ // have two copies of this thing. Probably after removing code from the
1383
+ // superclass that should not be there.
1282
1384
+ (BOOL )checkForError : (CHIP_ERROR)errorCode logMsg : (NSString *)logMsg error : (NSError * __autoreleasing *)error
1283
1385
{
1284
1386
if (CHIP_NO_ERROR == errorCode) {
@@ -1472,20 +1574,8 @@ - (BOOL)syncRunOnWorkQueueWithBoolReturnValue:(SyncWorkQueueBlockWithBoolReturnV
1472
1574
1473
1575
- (nullable NSNumber *)compressedFabricID
1474
1576
{
1475
- assertChipStackLockedByCurrentThread ();
1476
-
1477
- if (!_cppCommissioner) {
1478
- return nil ;
1479
- }
1480
-
1481
- return @(_cppCommissioner->GetCompressedFabricId ());
1482
- }
1483
-
1484
- - (NSNumber * _Nullable)syncGetCompressedFabricID
1485
- {
1486
- return [self syncRunOnWorkQueueWithReturnValue: ^NSNumber * {
1487
- return [self compressedFabricID ];
1488
- } error: nil ];
1577
+ auto storedValue = _storedCompressedFabricID.load ();
1578
+ return storedValue.has_value () ? @(storedValue.value ()) : nil ;
1489
1579
}
1490
1580
1491
1581
- (CHIP_ERROR)isRunningOnFabric : (chip::FabricTable *)fabricTable
0 commit comments