|
41 | 41 | #import "MTROperationalCredentialsDelegate.h"
|
42 | 42 | #import "MTRP256KeypairBridge.h"
|
43 | 43 | #import "MTRPersistentStorageDelegateBridge.h"
|
| 44 | +#import "MTRServerEndpoint_Internal.h" |
44 | 45 | #import "MTRSetupPayload.h"
|
45 | 46 | #import "NSDataSpanConversion.h"
|
46 | 47 | #import "NSStringSpanConversion.h"
|
@@ -121,6 +122,9 @@ @implementation MTRDeviceController {
|
121 | 122 | os_unfair_lock _deviceMapLock; // protects nodeIDToDeviceMap
|
122 | 123 | MTRCommissionableBrowser * _commissionableBrowser;
|
123 | 124 | MTRAttestationTrustStoreBridge * _attestationTrustStoreBridge;
|
| 125 | + |
| 126 | + // _serverEndpoints is only touched on the Matter queue. |
| 127 | + NSMutableArray<MTRServerEndpoint *> * _serverEndpoints; |
124 | 128 | }
|
125 | 129 |
|
126 | 130 | - (nullable instancetype)initWithParameters:(MTRDeviceControllerAbstractParameters *)parameters error:(NSError * __autoreleasing *)error
|
@@ -221,6 +225,7 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
|
221 | 225 | _factory = factory;
|
222 | 226 | _deviceMapLock = OS_UNFAIR_LOCK_INIT;
|
223 | 227 | _nodeIDToDeviceMap = [NSMutableDictionary dictionary];
|
| 228 | + _serverEndpoints = [[NSMutableArray alloc] init]; |
224 | 229 | _commissionableBrowser = nil;
|
225 | 230 |
|
226 | 231 | _deviceControllerDelegateBridge = new MTRDeviceControllerDelegateBridge();
|
@@ -285,6 +290,11 @@ - (void)shutDownCppController
|
285 | 290 | {
|
286 | 291 | assertChipStackLockedByCurrentThread();
|
287 | 292 |
|
| 293 | + // Shut down all our endpoints. |
| 294 | + for (MTRServerEndpoint * endpoint in [_serverEndpoints copy]) { |
| 295 | + [self removeServerEndpointOnMatterQueue:endpoint]; |
| 296 | + } |
| 297 | + |
288 | 298 | if (_cppCommissioner) {
|
289 | 299 | auto * commissionerToShutDown = _cppCommissioner;
|
290 | 300 | // Flag ourselves as not running before we start shutting down
|
@@ -947,6 +957,57 @@ - (NSData * _Nullable)attestationChallengeForDeviceID:(NSNumber *)deviceID
|
947 | 957 | return [self syncRunOnWorkQueueWithReturnValue:block error:nil];
|
948 | 958 | }
|
949 | 959 |
|
| 960 | +- (BOOL)addServerEndpoint:(MTRServerEndpoint *)endpoint |
| 961 | +{ |
| 962 | + VerifyOrReturnValue([self checkIsRunning], NO); |
| 963 | + |
| 964 | + if (![_factory addServerEndpoint:endpoint]) { |
| 965 | + return NO; |
| 966 | + } |
| 967 | + |
| 968 | + if (![endpoint associateWithController:self]) { |
| 969 | + MTR_LOG_ERROR("Failed to associate MTRServerEndpoint with MTRDeviceController"); |
| 970 | + [_factory removeServerEndpoint:endpoint]; |
| 971 | + return NO; |
| 972 | + } |
| 973 | + |
| 974 | + [self asyncDispatchToMatterQueue:^() { |
| 975 | + [self->_serverEndpoints addObject:endpoint]; |
| 976 | + [endpoint registerMatterEndpoint]; |
| 977 | + } |
| 978 | + errorHandler:^(NSError * error) { |
| 979 | + MTR_LOG_ERROR("Unexpected failure dispatching to Matter queue on running controller in addServerEndpoint"); |
| 980 | + }]; |
| 981 | + return YES; |
| 982 | +} |
| 983 | + |
| 984 | +- (void)removeServerEndpoint:(MTRServerEndpoint *)endpoint queue:(dispatch_queue_t)queue completion:(dispatch_block_t)completion MTR_NEWLY_AVAILABLE |
| 985 | +{ |
| 986 | + VerifyOrReturn([self checkIsRunning]); |
| 987 | + |
| 988 | + // We need to unhook the endpoint from the Matter side before we can start |
| 989 | + // tearing it down. |
| 990 | + [self asyncDispatchToMatterQueue:^() { |
| 991 | + [self removeServerEndpointOnMatterQueue:endpoint]; |
| 992 | + dispatch_async(queue, completion); |
| 993 | + } |
| 994 | + errorHandler:^(NSError * error) { |
| 995 | + // Error means we got shut down, so the endpoint is removed now. |
| 996 | + dispatch_async(queue, completion); |
| 997 | + }]; |
| 998 | +} |
| 999 | + |
| 1000 | +- (void)removeServerEndpointOnMatterQueue:(MTRServerEndpoint *)endpoint |
| 1001 | +{ |
| 1002 | + assertChipStackLockedByCurrentThread(); |
| 1003 | + |
| 1004 | + [endpoint unregisterMatterEndpoint]; |
| 1005 | + [_serverEndpoints removeObject:endpoint]; |
| 1006 | + [endpoint invalidate]; |
| 1007 | + |
| 1008 | + [_factory removeServerEndpoint:endpoint]; |
| 1009 | +} |
| 1010 | + |
950 | 1011 | - (BOOL)checkForInitError:(BOOL)condition logMsg:(NSString *)logMsg
|
951 | 1012 | {
|
952 | 1013 | if (condition) {
|
@@ -1230,6 +1291,43 @@ - (void)downloadLogFromNodeWithID:(NSNumber *)nodeID
|
1230 | 1291 | completion:completion];
|
1231 | 1292 | }
|
1232 | 1293 |
|
| 1294 | +- (NSArray<MTRAccessGrant *> *)accessGrantsForClusterPath:(MTRClusterPath *)clusterPath |
| 1295 | +{ |
| 1296 | + assertChipStackLockedByCurrentThread(); |
| 1297 | + |
| 1298 | + for (MTRServerEndpoint * endpoint in _serverEndpoints) { |
| 1299 | + if ([clusterPath.endpoint isEqual:endpoint.endpointID]) { |
| 1300 | + return [endpoint matterAccessGrantsForCluster:clusterPath.cluster]; |
| 1301 | + } |
| 1302 | + } |
| 1303 | + |
| 1304 | + // Nothing matched, no grants. |
| 1305 | + return @[]; |
| 1306 | +} |
| 1307 | + |
| 1308 | +- (nullable NSNumber *)neededReadPrivilegeForClusterID:(NSNumber *)clusterID attributeID:(NSNumber *)attributeID |
| 1309 | +{ |
| 1310 | + assertChipStackLockedByCurrentThread(); |
| 1311 | + |
| 1312 | + for (MTRServerEndpoint * endpoint in _serverEndpoints) { |
| 1313 | + for (MTRServerCluster * cluster in endpoint.serverClusters) { |
| 1314 | + if (![cluster.clusterID isEqual:clusterID]) { |
| 1315 | + continue; |
| 1316 | + } |
| 1317 | + |
| 1318 | + for (MTRServerAttribute * attr in cluster.attributes) { |
| 1319 | + if (![attr.attributeID isEqual:attributeID]) { |
| 1320 | + continue; |
| 1321 | + } |
| 1322 | + |
| 1323 | + return @(attr.requiredReadPrivilege); |
| 1324 | + } |
| 1325 | + } |
| 1326 | + } |
| 1327 | + |
| 1328 | + return nil; |
| 1329 | +} |
| 1330 | + |
1233 | 1331 | @end
|
1234 | 1332 |
|
1235 | 1333 | /**
|
|
0 commit comments