Общие сведения об арене
С точки зрения разработчика решения на базе KasperskyOS арена IPC-сообщений представляет собой байтовый буфер в памяти процесса, предназначенный для хранения передаваемых через IPC данных переменного размера, то есть входных, выходных и error-параметров интерфейсных методов (и/или элементов этих параметров), которые имеют IDL-типы переменного размера. Также арена используется при обращении к модулю безопасности Kaspersky Security Module для хранения входных параметров методов интерфейса безопасности (и/или элементов этих параметров), которые имеют IDL-типы переменного размера. (Параметры интерфейсных методов постоянного размера хранятся в фиксированной части IPC-сообщения.) Арены используются как на стороне клиента, так и на стороне сервера. Одна арена предназначена либо для передачи, либо для приема через IPC данных переменного размера, но не для передачи и приема этих данных одновременно, то есть условно арены можно разделить на арены IPC-запросов (содержат входные параметры интерфейсных методов) и арены IPC-ответов (содержат выходные и error-параметры интерфейсных методов).
Через IPC передается только использованная часть арены, то есть занятая данными. (При отсутствии данных арена не передается.) Использованная часть арены включает один или несколько участков. В одном участке арены хранится массив объектов одного типа, например, массив однобайтовых объектов или массив структур. В разных участках арены могут храниться массивы объектов разного типа. Адрес начала арены должен быть выравнен на границу 2^N-байтовой последовательности, где 2^N – значение, которое больше либо равно размеру наибольшего примитивного типа в арене (например, наибольшего поля примитивного типа в структуре). Адрес участка арены также должен быть выравнен на границу 2^N-байтовой последовательности, где 2^N – значение, которое больше либо равно размеру наибольшего примитивного типа в участке арены.
Необходимость наличия нескольких участков в арене возникает, если интерфейсный метод имеет несколько входных, выходных или error-параметров переменного размера, а также если несколько элементов входных, выходных или error-параметров интерфейсного метода имеют переменный размер. Например, если интерфейсный метод имеет входной параметр IDL-типа sequence
и входной параметр IDL-типа bytes
, то в арене IPC-запросов будет как минимум два участка, но могут потребоваться и дополнительные участки, если параметр IDL-типа sequence
состоит из элементов IDL-типа переменного размера (например, string
, то есть элементами последовательности являются строковые буферы). Также, к примеру, если интерфейсный метод имеет один выходной параметр IDL-типа struct
, который содержит два поля типа bytes
и string
, то в арене IPC-ответов будет два участка.
Из-за выравнивания адресов участков арены между этими участками могут появляться неиспользованные промежутки, поэтому размер использованной части арены может превышать размер помещенных в нее данных.
API для работы с ареной
Набор функций и макросов для работы с ареной определен в заголовочном файле sysroot-*-kos/include/nk/arena.h
из состава KasperskyOS SDK. Также функция для копирования строки в арену объявлена в заголовочном файле sysroot-*-kos/include/coresrv/nk/transport-kos.h
из состава KasperskyOS SDK.
Сведения о функциях и макросах, определенных в заголовочном файле sysroot-*-kos/include/nk/arena.h
, приведены в таблице ниже. В этих функциях и макросах арена и участок арены идентифицируются дескриптором арены (тип nk_arena
) и дескриптором участка арены (тип nk_ptr_t
) соответственно. Дескриптор арены представляет собой структуру, содержащую три указателя: на начало арены, на начало неиспользованной части арены и на конец арены. Дескриптор участка арены представляет собой структуру, содержащую смещение участка арены в байтах (относительно начала арены) и размер участка арены в байтах. (Тип дескриптора участка арены определен в заголовочном файле sysroot-*-kos/include/nk/types.h
. из состава KasperskyOS SDK.)
Создание арены
Чтобы передавать через IPC параметры интерфейсных методов переменного размера, нужно создать арены как на стороне клиента, так и на стороне сервера. (При обработке IPC-запросов на стороне сервера с использованием функции NkKosDoDispatch()
, определенной в заголовочном файле sysroot-*-kos/include/coresrv/nk/transport-kos-dispatch.h
из состава KasperskyOS SDK, арены IPC-запросов и IPC-ответов создаются автоматически.)
Чтобы создать арену, нужно создать буфер (в стеке или куче) и инициализировать дескриптор арены.
Адрес буфера должен быть выравнен так, чтобы удовлетворять максимальному размеру примитивного типа, который может быть помещен в этот буфер. Адрес буфера, созданного динамически, обычно имеет достаточное выравнивание для помещения в этот буфер данных примитивного типа максимального размера. Чтобы обеспечить требуемое выравнивание адреса статически созданного буфера, можно использовать спецификатор alignas
.
Чтобы инициализировать дескриптор арены, используя указатель на уже созданный буфер, нужно использовать функцию или макрос API:
NK_ARENA_INITIALIZER()
;nk_arena_init()
;nk_arena_create()
;NK_ARENA_FINAL()
;nk_arena_init_final()
.Тип указателя не имеет значения, поскольку в коде функций и макросов API этот указатель приводится к указателю на однобайтовый объект.
Макрос NK_ARENA_INITIALIZER()
и функции nk_arena_init()
и nk_arena_create()
инициализируют дескриптор арены, которая может содержать один и более участков. Макросы NK_ARENA_FINAL()
и nk_arena_init_final()
инициализируют дескриптор арены, которая на протяжении всего своего жизненного цикла содержит только один участок, занимающий всю арену.
Чтобы создать буфер в стеке и инициализировать дескриптор одним шагом, нужно использовать макрос NK_ARENA_AUTO()
. Этот макрос создает арену, которая может содержать один и более участков, а адрес буфера, созданного этим макросом, имеет достаточное выравнивание для помещения в этот буфер данных примитивного типа максимального размера.
Размер арены должен быть достаточен, чтобы с учетом выравнивания адресов участков вместить параметры переменного размера для IPC-запросов или IPC-ответов одного интерфейсного метода или множества интерфейсных методов, соответствующих одному интерфейсу, компоненту или классу процессов. Автоматически генерируемый транспортный код (заголовочные файлы *.idl.h
, *.cdl.h
, *.edl.h
) содержит константы *_arena_size
, значения которых гарантированно соответствуют достаточным размерам арен в байтах.
Заголовочные файлы *.idl.h
, *.cdl.h
, *.edl.h
содержат следующие константы *_arena_size
:
<имя интерфейса>_<имя интерфейсного метода>_req_arena_size
– размер арены IPC-запросов для указанного интерфейсного метода указанного интерфейса;<имя интерфейса>_<имя интерфейсного метода>_res_arena_size
– размер арены IPC-ответов для указанного интерфейсного метода указанного интерфейса;<имя интерфейса>_req_arena_size
– размер арены IPC-запросов для любого интерфейсного метода указанного интерфейса;<имя интерфейса>_res_arena_size
– размер арены IPC-ответов для любого интерфейсного метода указанного интерфейса.Заголовочные файлы *.cdl.h
, *.edl.h
дополнительно содержат следующие константы *_arena_size
:
<имя компонента>_component_req_arena_size
– размер арены IPC-запросов для любого интерфейсного метода указанного компонента;<имя компонента>_component_res_arena_size
– размер арены IPC-ответов для любого интерфейсного метода указанного компонента.Заголовочные файлы *.edl.h
дополнительно содержат следующие константы *_arena_size
:
<имя класса процессов>_entity_req_arena_size
– размер арены IPC-запросов для любого интерфейсного метода указанного класса процессов;<имя класса процессов>_entity_res_arena_size
– размер арены IPC-ответов для любого интерфейсного метода указанного класса процессов.Константы, содержащие размер арены IPC-запросов или IPC-ответов для одного интерфейсного метода (<имя интерфейса>_<имя интерфейсного метода>_req_arena_size
и <имя интерфейса>_<имя интерфейсного метода>_res_arena_size
), предназначены для использования на стороне клиента. Остальные константы могут использоваться как на стороне клиента, так и на стороне сервера.
Примеры создания арены:
/* Пример 1 */
alignas(8) char reqBuffer[Write_WriteInLog_req_arena_size];
struct nk_arena reqArena = NK_ARENA_INITIALIZER(
reqBuffer, reqBuffer + sizeof(reqBuffer));
/* Пример 2 */
struct nk_arena res_arena;
char res_buf[kl_rump_DhcpcdConfig_GetOptionNtpServers_res_arena_size];
nk_arena_init(&res_arena, res_buf, res_buf + sizeof(res_buf));
/* Пример 3 */
char req_buffer[kl_CliApplication_Run_req_arena_size];
struct nk_arena req_arena = nk_arena_create(req_buffer, sizeof(req_buffer));
/* Пример 4 */
nk_ptr_t ptr;
const char *cstr = "example";
nk_arena arena = NK_ARENA_FINAL(&ptr, cstr, strlen(cstr));
/* Пример 5 */
const char *path = "path_to_file";
size_t len = strlen(path);
/* Структура для сохранения фиксированной части IPC-запроса */
struct kl_VfsFilesystem_Rmdir_req req;
struct nk_arena req_arena;
nk_arena_init_final(&req_arena, &req.path, path, len);
/* Пример 6 */
struct nk_arena res_arena = NK_ARENA_AUTO(kl_Klog_component_res_arena_size);
Заполнение арены данными перед передачей через IPC
Перед передачей IPC-запроса на стороне клиента или IPC-ответа на стороне сервера арену нужно заполнить данными. Если для создания арены используется макрос NK_ARENA_FINAL()
или nk_arena_init_final()
, то резервировать участок арены не требуется, а нужно только заполнить этот участок данными. Если для создания арены используется макрос NK_ARENA_INITIALIZER()
или NK_ARENA_AUTO()
либо функция nk_arena_init()
или nk_arena_create()
, то в арене необходимо зарезервировать один или несколько участков, чтобы поместить в них данные. Чтобы зарезервировать участок арены, нужно использовать функцию или макрос API:
__nk_arena_alloc()
;nk_arena_store()
;__nk_arena_store()
;nk_arena_alloc()
;NkKosCopyStringToArena()
.Дескриптор участка арены, который передается через выходной параметр этих функций и макросов, а также макросов NK_ARENA_FINAL()
и nk_arena_init_final()
, нужно поместить в фиксированную часть либо в арену IPC-сообщения. Если интерфейсный метод имеет параметр переменного размера, то фиксированная часть IPC-сообщений вместо самого параметра содержит дескриптор участка арены, в котором находится этот параметр. Если интерфейсный метод имеет параметр постоянного размера с элементами переменного размера, то фиксированная часть IPC-сообщений вместо самих элементов параметра содержит дескрипторы участков арены, в которых находятся эти элементы параметра. Если интерфейсный метод имеет параметр переменного размера, содержащий элементы переменного размера, то фиксированная часть IPC-сообщений содержит дескриптор участка арены, в котором находятся дескрипторы других участков арены, содержащих эти элементы параметра.
Макрос nk_arena_store()
и функции __nk_arena_store()
и NkKosCopyStringToArena()
не только резервируют участок арены, но и копируют данные в этот участок.
Макрос nk_arena_alloc()
позволяет получить адрес зарезервированного участка арены. Также адрес участка арены можно получить, используя функцию __nk_arena_get()
или макрос nk_arena_get()
, которые дополнительно через выходной параметр передают размер арены.
Зарезервированный участок арены можно уменьшить. Для этого нужно использовать макрос nk_arena_shrink()
или функцию _nk_arena_shrink()
.
Чтобы отменить текущее резервирование участков арены для последующего резервирования новых участков под другие данные (после отправки IPC-сообщения), нужно вызвать функцию nk_arena_reset()
. Если для создания арены используется макрос NK_ARENA_FINAL()
или nk_arena_init_final()
, то отменять резервирование участка не требуется, так как такая арена на протяжении всего своего жизненного цикла содержит один участок, занимающий всю арену.
Примеры заполнения арены данными:
/* Пример 1 */
char req_buffer[kl_rump_NpfctlFilter_TableAdd_req_arena_size];
struct nk_arena req_arena = NK_ARENA_INITIALIZER(req_buffer, req_buffer + sizeof(req_buffer));
/* Структура для сохранения фиксированной части IPC-запроса */
struct kl_rump_NpfctlFilter_TableAdd_req req;
if (nk_arena_store(char, &req_arena, &req.tid, tid, tidlen))
return ENOMEM;
if (nk_arena_store(char, &req_arena, &req.cidrAddr, cidr_addr, cidr_addrlen))
return ENOMEM;
/* Пример 2 */
char req_arena_buf[StringMaxSize];
struct nk_arena req_arena = NK_ARENA_INITIALIZER(req_arena_buf,
req_arena_buf + sizeof(req_arena_buf));
/* Структура для сохранения фиксированной части IPC-запроса */
kl_drivers_FBConsole_SetFont_req req;
size_t buf_size = strlen(fileName) + 1;
char *buf = nk_arena_alloc(char, &req_arena, &req.fileName, buf_size);
memcpy(buf, fileName, buf_size);
/* Пример 3 */
char reqArenaBuf[kl_core_DCM_req_arena_size];
struct nk_arena reqArena
= NK_ARENA_INITIALIZER(reqArenaBuf,
reqArenaBuf + sizeof(reqArenaBuf));
/* Структура для сохранения фиксированной части IPC-запроса */
kl_core_DCM_Subscribe_req req;
rc = NkKosCopyStringToArena(&reqArena, &req.endpointType, endpointType);
if (rc != rcOk)
return rc;
rc = NkKosCopyStringToArena(&reqArena, &req.endpointName, endpointName);
if (rc != rcOk)
return rc;
rc = NkKosCopyStringToArena(&reqArena, &req.serverName, serverName);
if (rc != rcOk)
return rc;
/* Пример 4 */
unsigned counter = 0;
nk_ptr_t *paths;
/* Резервирование участка арены для дескрипторов других участков арены */
paths = nk_arena_alloc(nk_ptr_t, resArena, &res->logRes, msgCount);
while(...)
{
...
/* Резервирование участков арены с сохранением их дескрипторов в
* ранее зарезервированном участке арены с адресом paths */
char *str = nk_arena_alloc(
char,
resArena,
&paths[counter],
stringLength + 1);
if (str == NK_NULL)
return NK_ENOMEM;
snprintf(str, (stringLength + 1), "%s", buffer);
...
counter++;
}
Получение данных из арены после приема через IPC
Перед получением IPC-запроса на стороне сервера или IPC-ответа на стороне клиента для арены, в которую будут помещены полученные через IPC-данные, нужно отменить текущее резервирование участков, вызвав функцию nk_arena_reset()
. Это требуется сделать, даже если для создания арены используется макрос NK_ARENA_FINAL()
или nk_arena_init_final()
. (Макросы NK_ARENA_INITIALIZER()
и NK_ARENA_AUTO()
, а также функции nk_arena_init()
и nk_arena_create()
создают арену без зарезервированных участков. Перед однократном использовании такой арены для сохранения полученных через IPC данных вызывать функцию nk_arena_reset()
не требуется.)
Чтобы получить указатели на участки арены и размеры этих участков, нужно использовать функцию __nk_arena_get()
или макрос nk_arena_get()
, передавая через входной параметр соответствующие дескрипторы участков арены, полученные из фиксированной части и арены IPC-сообщения.
Пример получения данных из арены:
struct nk_arena res_arena;
char res_buf[kl_rump_DhcpcdConfig_Version_res_ver_size];
nk_arena_init(&res_arena, res_buf, res_buf + sizeof(res_buf));
/* Структура для сохранения IPC-запроса */
struct kl_rump_DhcpcdConfig_Version_req req;
req.buflen = buflen;
/* Структура для сохранения IPC-ответа */
struct kl_rump_DhcpcdConfig_Version_res res;
/* Вызов интерфейсного метода */
if (kl_rump_DhcpcdConfig_Version(dhcpcd.proxy, &req, NULL, &res, &res_arena) != NK_EOK)
return -1;
size_t ptrlen;
char *ptr = nk_arena_get(char, &res_arena, &res.ver, &ptrlen);
memcpy(buf, ptr, ptrlen);
Дополнительные возможности API
Чтобы получить размер арены, нужно вызвать функцию nk_arena_capacity()
.
Чтобы получить размер использованной части арены, нужно вызвать функцию nk_arena_allocated_size()
.
Чтобы проверить, является ли корректным дескриптор участка арены, нужно использовать макрос nk_arena_validate()
или функцию __nk_arena_validate()
.
Сведения о функциях и макросах API
Функции и макросы arena.h
Функция/Макрос |
Сведения о функции/макросе |
---|---|
|
Назначение Инициализирует дескриптор арены. Параметры
Значения макроса Код инициализации дескриптора арены. |
|
Назначение Инициализирует дескриптор арены. Параметры
Возвращаемые значения Нет. |
|
Назначение Создает и инициализирует дескриптор арены. Параметры
Возвращаемые значения Дескриптор арены. |
|
Назначение Создает в стеке буфер, а также создает и инициализирует дескриптор арены. Параметры
Значения макроса Дескриптор арены. |
|
Назначение Инициализирует дескриптор арены, содержащей только один участок. Параметры
Значения макроса Дескриптор арены. |
|
Назначение Отменяет резервирование участков арены. Параметры
Возвращаемые значения Нет. |
|
Назначение Резервирует участок арены заданного размера с заданным выравниванием. Параметры
Возвращаемые значения В случае успеха возвращает |
|
Назначение Позволяет получить размер арены. Параметры
Возвращаемые значения Размер арены в байтах. Дополнительные сведения Если параметр имеет значение |
|
Назначение Проверяет, является ли корректным дескриптор участка арены. Параметры
Значения макроса Имеет значение
Имеет значение
Имеет значение |
|
Назначение Проверяет, является ли корректным дескриптор участка арены. Параметры
Возвращаемые значения Возвращает
Возвращает
Возвращает |
|
Назначение Позволяет получить указатель на участок арены и размер этого участка. Параметры
Возвращаемые значения Указатель на участок арены или |
|
Назначение Позволяет получить размер использованной части арены. Параметры
Возвращаемые значения Размер использованной части арены в байтах. Дополнительные сведения Если параметр имеет значение |
|
Назначение Резервирует участок арены для заданного числа объектов заданного типа и копирует эти объекты в зарезервированный участок. Параметры
Значения макроса В случае успеха имеет значение |
|
Назначение Резервирует участок арены с заданным выравниванием для данных заданного размера и копирует эти данные в зарезервированный участок. Параметры
Возвращаемые значения В случае успеха возвращает |
|
Назначение Инициализирует дескриптор арены, содержащей только один участок. Параметры
Значения макроса Нет. |
|
Назначение Резервирует участок арены для заданного числа объектов заданного типа. Параметры
Значения макроса В случае успеха имеет значение адреса зарезервированного участка арены, иначе имеет значение |
|
Назначение Позволяет получить адрес участка арены и число объектов заданного типа, которое вмещается в этом участке. Параметры
Значения макроса В случае успеха имеет значение адреса участка арены, иначе имеет значение Дополнительные сведения Если размер участка арены не кратен размеру типа объектов, для которых этот участок предназначен, имеет значение |
|
Назначение Уменьшает размер участка арены. Параметры
Значения макроса В случае успеха имеет значение адреса уменьшенного участка арены, иначе имеет значение Дополнительные сведения Если требуемый размер участка арены превышает текущий, имеет значение Если выравнивание участка арены, который нужно уменьшить, не удовлетворяет типу объектов, для которых предназначен уменьшенный участок, имеет значение Если участок арены, который нужно уменьшить, является последним в арене, то освободившаяся часть этого участка становится доступной для резервирования последующих участков. |
|
Назначение Уменьшает размер участка арены. Параметры
Возвращаемые значения В случае успеха возвращает адрес уменьшенного участка арены, иначе возвращает Дополнительные сведения Если требуемый размер участка арены превышает текущий, возвращает Если выравнивание участка арены, который нужно уменьшить, не удовлетворяет заданному выравниванию, возвращает Если участок арены, который нужно уменьшить, является последним в арене, то освободившаяся часть этого участка становится доступной для резервирования последующих участков. |