Skip to content

Commit

Permalink
Modify Matter.framework to allow per-controller storage.
Browse files Browse the repository at this point in the history
This also allows starting multiple controllers with different node IDs on a
single fabric.

Public API changes:

* It's now possible to initialize MTRDeviceControllerFactoryParams without
  storage.  When a factory is then started with those params, it will expect
  storage to be provided for every controller that is created.
* Controllers to be created in the new setup use
  MTRDeviceControllerStartupParameters, not MTRDeviceControllerStartupParams.
* When starting a controller, API clients provide a UUID for that controller
  (which is then exposed on the MTRDeviceController) and a storage delegate.
* For now, the only supported controller startup mode is for the client to
  provide the full certificate chain, operational key and vendor ID, via
  MTRDeviceControllerExternalCertificateStartupParameters.  For controllers that
  will commission devices, that means also providing an
  MTROperationalCertificateIssuer.
* The new "create a controller" API is called createController.
* The new MTRDeviceControllerStorageDelegate API provides some context for the
  key/value pairs in terms of whether they need to be stored in encrypted
  storage or not, and whether they can be shared across multiple devices and
  under what conditions.

Implementation notes:

* MTRDemuxingStorage handles directing storage requests to the right
  per-controller storage object.
* MTRDeviceControllerDataStore wraps the raw storage delegate and provides a
  semantic API on top of its key/value storage for the storage operations we
  actually want to perform.
* MTRSessionResumptionStorageBridge implements session resumption storage,
  acting as an adapter between the Matter session resumption storage API and
  MTRDeviceControllerDataStore.  In particular, it happens locating the right
  controller(s) to talk to and so on.  This avoids dealing with the default
  Matter implementation's use of non-fabric-index-scoped keys for storing
  session resumption information.

Fixes project-chip#27394
  • Loading branch information
bzbarsky-apple committed Aug 28, 2023
1 parent abe94e7 commit ffc2220
Show file tree
Hide file tree
Showing 20 changed files with 3,048 additions and 67 deletions.
109 changes: 109 additions & 0 deletions src/darwin/Framework/CHIP/MTRDemuxingStorage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* 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/MTRDeviceControllerFactory.h>

#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/core/DataModelTypes.h>

NS_ASSUME_NONNULL_BEGIN

/**
* A PersistentStorageDelegate implementation that does the following:
*
* 1) Ensures that any "global" storage keys are stored in RAM as needed so that
* the Matter stack has access to them.
* 2) Hands off fabric-index-specific keys to the controller that corresponds to
* that fabric index, if any.
*/
class MTRDemuxingStorage : public chip::PersistentStorageDelegate {
public:
MTRDemuxingStorage(MTRDeviceControllerFactory * factory);
~MTRDemuxingStorage() {}

// PersistentStorageDelegate API.
CHIP_ERROR SyncGetKeyValue(const char * key, void * buffer, uint16_t & size) override;

CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override;

CHIP_ERROR SyncDeleteKeyValue(const char * key) override;

private:
static bool IsGlobalKey(NSString * key);

/**
* Checks for a key that is scoped to a specific fabric index.
*/
static bool IsIndexSpecificKey(NSString * key);

/**
* Extracts the fabric index from an index-specific key. Fails if the key
* is not index-specific or if a numeric FabricIndex could not be extracted
* from it.
*/
static CHIP_ERROR ExtractIndexFromKey(NSString * key, chip::FabricIndex * index);

/**
* Extracts the "index-specific" part of an index-specific key (i.e. the
* part after "f/index/").
*/
static CHIP_ERROR ExtractIndexSpecificKey(NSString * key, NSString * _Nullable __autoreleasing * _Nonnull extractedKey);

/**
* Methods for reading/writing/deleting things. The index-specific ones
* will have the "f/index/" bit already stripped of from the front of the key.
*/
NSData * _Nullable GetGlobalValue(NSString * key);
NSData * _Nullable GetIndexSpecificValue(chip::FabricIndex index, NSString * key);

CHIP_ERROR SetGlobalValue(NSString * key, NSData * data);
CHIP_ERROR SetIndexSpecificValue(chip::FabricIndex index, NSString * key, NSData * data);

CHIP_ERROR DeleteGlobalValue(NSString * key);
CHIP_ERROR DeleteIndexSpecificValue(chip::FabricIndex index, NSString * key);

/**
* Method to test whether a global key should be stored in memory only, as
* opposed to being passed on to the actual storage related to controllers.
*/
static bool IsMemoryOnlyGlobalKey(NSString * key);

/**
* Method to test whether an index-specific key should be stored in memory only, as
* opposed to being passed on to the actual storage related to controllers.
* The key string will ahve the "f/index/" bit already stripped off the
* front of the key.
*/
static bool IsMemoryOnlyIndexSpecificKey(NSString * key);

/**
* Methods for modifying our in-memory store for fully qualified keys.
*/
NSData * _Nullable GetInMemoryValue(NSString * key);
CHIP_ERROR SetInMemoryValue(NSString * key, NSData * data);
CHIP_ERROR DeleteInMemoryValue(NSString * key);

/**
* Method to convert an index-specific key into a fully qualified key.
*/
static NSString * FullyQualifiedKey(chip::FabricIndex index, NSString * key);

MTRDeviceControllerFactory * mFactory;
NSMutableDictionary<NSString *, NSData *> * mInMemoryStore;
};

NS_ASSUME_NONNULL_END
Loading

0 comments on commit ffc2220

Please sign in to comment.