kvstore_global_api (Static Global API)
Applications should use the KVStore static API to access the instances of KVStore components that the selected configuration allocates.
Allocation of KVStore components
The function kv_init_storage_config()
allocates and initializes all the components required for the execution of the global API. The API implicitly calls it and can call it several times without side effects.
The configuration parameters present in the API's .json
files determine the allocation and setup of required KVStore components and block devices. The application's .json
file, mbed_app.json
, can override these parameters. Please see the storage configuration documentation for details.
Parameter details
Below are the nontrivial parameters that are part of the global API.
full_name_key
This is a string composed of characters valid for file names in the form of /path/myfilename.
The global API uses /path/ to identify the KVStore component that receives the call. The global API removes the /path/ from the string passed to the KVStore API. The path string must be equal to the string defined for the default_kv parameter in the API's mbed_lib.json
file (/kv/
by default). Use /kv/myfilename when using the default configuration.
Note: The configuration passes the value of the parameter default_kv
to the function kv_map.attach(STR(MBED_CONF_STORAGE_DEFAULT_KV),&kvstore_config)
to create the relation between the path string and the allocated KVStore component.
Creation flags
You can "or" (|) the flags below and pass them to the function set in the parameter create_flags
. These flags indicate the security required for the data saved. You can override this security behavior by explicitly selecting a configuration in the storage_type
parameter:
- KV_WRITE_ONCE_FLAG: The system does not an additional call to the function set with the same file name to delete or replace data.
- KV_REQUIRE_CONFIDENTIALITY_FLAG: The system encrypts the data using an AES CTR, a random IV and a key derived from DeviceKey. This flag will be ignored if you select the
TDB_INTERNAL
configuration because the internal memory is seen as protected from physical attacks. - KV_REQUIRE_REPLAY_PROTECTION_FLAG: The system keeps a copy of the data CMAC in internal memory and checks that the data CMAC corresponds to this saved CMAC. It does this to prevent an attacker replacing the latest data with a valid old version of the data.
full_prefix
This parameter is used in the iterator kv_iterator_open
function to define the subset of file names that kv_iterator_next
returns. The string is used as a prefix, and kv_iterator_next
returns each name that starts with the exact string passed in full_prefix
.
Note: The full_prefix string must include the /path/
. For example: /kv/
.
Static Global API class reference
Static Global API example
/* Copyright (c) 2018 Arm Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#include "mbed.h"
#include <stdio.h>
#include <string.h>
#include "KVStore.h"
#include "kvstore_global_api.h"
#include "DeviceKey.h"
using namespace mbed;
#define EXAMPLE_KV_VALUE_LENGTH 64
#define EXAMPLE_KV_KEY_LENGTH 32
#define err_code(res) MBED_GET_ERROR_CODE(res)
#define STR_EXPAND(tok) #tok
#define STR(tok) STR_EXPAND(tok)
void kv_store_global_api_example();
int main()
{
/* KV Store Static API Example */
kv_store_global_api_example();
}
void kv_store_global_api_example()
{
char kv_value_in[EXAMPLE_KV_VALUE_LENGTH] = {"kvstore_dummy_value_hello_world"};
char kv_key_in[EXAMPLE_KV_KEY_LENGTH] = {"/kv/dummy_key1"};
char kv_key_out[EXAMPLE_KV_KEY_LENGTH] = {0};
size_t actual_size = 0;
/* key information container */
kv_info_t info;
/* kv store iterator */
kv_iterator_t kvstore_it;
int i_ind = 0;
printf("--- Mbed OS KVStore static API example ---\n");
int res = MBED_ERROR_NOT_READY;
/* Start By Resetting the KV Storage */
printf("kv_reset\n");
res = kv_reset("/kv/");
printf("kv_reset -> %d\n", err_code(res));
if (strcmp(STR(MBED_CONF_STORAGE_STORAGE_TYPE), "TDB_EXTERNAL") == 0) {
res = DeviceKey::get_instance().generate_root_of_trust();
printf("DeviceKey::get_instance().generate_root_of_trust() -> %d\n", res);
}
/* Set First 'Dummy' Key/Value pair with unprotected clear value data */
printf("kv_set first dummy key\n");
res = kv_set(kv_key_in, kv_value_in, strlen(kv_value_in), 0);
printf("kv_set -> %d\n", err_code(res));
/* Read the KV Pair you've just set */
/* Start by getting key's information */
printf("kv_get_info of first key\n");
res = kv_get_info(kv_key_in, &info);
printf("kv_get_info -> %d\n", err_code(res));
printf("kv_get_info key: %s\n", kv_key_in);
printf("kv_get_info info - size: %u, flags: %lu\n", info.size, info.flags);
/* Now that you know the data value size of this key,
* allocate a buffer with matching size and get the value data */
printf("kv_get first key\n");
char *kv_first_value_out = new char[info.size + 1];
memset(kv_first_value_out, 0, info.size + 1);
res = kv_get(kv_key_in, kv_first_value_out, info.size, &actual_size);
printf("kv_get -> %d\n", err_code(res));
printf("kv_get key: %s\n", kv_key_in);
printf("kv_get value: %s\n", kv_first_value_out);
delete[] kv_first_value_out;
/* Lets set some more 'Dummy' and 'Real' KV pairs */
/* Set 'Dummy' Key2 */
printf("kv_set second dummy key \n");
res = kv_set("/kv/dummy_key2", "dummy_value2", strlen("dummy_value2"), 0);
printf("kv_set -> %d\n", err_code(res));
/* Set an authenticated-encrypted 'Dummy' key with Replay protection */
printf("kv_set third key with Confidentiality and Replay Protection flags\n");
res = kv_set("/kv/dummy_auth_enc_key", "auth_enc_value", strlen("auth_enc_value"),
KV_REQUIRE_CONFIDENTIALITY_FLAG | KV_REQUIRE_REPLAY_PROTECTION_FLAG);
printf("kv_set -> %d\n", err_code(res));
/* Set 2 non-dummy 'Real' KV pairs */
/* Set 'Real' Key 1 */
printf("kv_set Set 'Real' Key 1\n");
res = kv_set("/kv/real_key1", "real_value1", strlen("real_value1"), 0);
printf("kv_set -> %d\n", err_code(res));
/* Set 'Real' Write-Once Key2 for a key that you do not want to be removed */
printf("kv_set Set 'Real' Key 2 with flag write-once\n");
res = kv_set("/kv/real_wo_key", "real_wo_value", strlen("real_wo_value"), KV_WRITE_ONCE_FLAG);
printf("kv_set -> %d\n", err_code(res));
/* Now lets remove all of the 'Dummy' Keys and remain with the 'Real' ones */
printf("Removing 'Dummy' Keys\n");
/* Iterate and remove Keys that start with prefix 'dummy' */
res = kv_iterator_open(&kvstore_it, "dummy");
memset(kv_key_out, 0, EXAMPLE_KV_KEY_LENGTH);
while (kv_iterator_next(kvstore_it, kv_key_out, EXAMPLE_KV_KEY_LENGTH) != MBED_ERROR_ITEM_NOT_FOUND) {
i_ind++;
printf("%d) Removing %s\n", i_ind, kv_key_out);
kv_remove(kv_key_out);
memset(kv_key_out, 0, EXAMPLE_KV_KEY_LENGTH);
}
res = kv_iterator_close(kvstore_it);
printf("Remaining with 'Real' Keys:\n");
/* Iterate on all remaining Keys */
res = kv_iterator_open(&kvstore_it, NULL);
memset(kv_key_out, 0, EXAMPLE_KV_KEY_LENGTH);
i_ind = 0;
while (kv_iterator_next(kvstore_it, kv_key_out, EXAMPLE_KV_KEY_LENGTH) != MBED_ERROR_ITEM_NOT_FOUND) {
i_ind++;
printf("%d) %s\n", i_ind, kv_key_out);
memset(kv_key_out, 0, EXAMPLE_KV_KEY_LENGTH);
}
res = kv_iterator_close(kvstore_it);
/* Try to remove write-once Key - should fail */
printf("kv_remove write-once file - should fail!\n");
res = kv_remove("/kv/real_wo_key");
printf("kv_remove -> %d\n", err_code(res));
/* Finally, reset will format kvstore and remove All Keys (including write-once keys) */
printf("kv_reset format kvstore (including write-once)\n");
res = kv_reset("/kv/");
printf("kv_reset -> %d\n", err_code(res));
return;
}