Инициализация IPC-транспорта для межпроцессного взаимодействия и управление обработкой IPC-запросов (transport-kos.h, transport-kos-dispatch.h)

30 сентября 2026

ID libkos_ipc_transport_api

API определены в заголовочных файлах transport-kos.h и transport-kos-dispatch.h из состава KasperskyOS SDK, которые расположены по пути sysroot-*-kos/include/coresrv/nk.

Возможности API:

Сведения о функциях API приведены в таблицах ниже.

В этом разделе приведены примеры использования API. В этих примерах используются динамически и статически созданные IPC-каналы, а программы, которые являются серверами, имеют следующую формальную спецификацию:

FsDriver.edl

task class FsDriver

components {

operationsComp : Operations

}

Operations.cdl

component Operations

endpoints {

fileOperations : FileIface

}

FileIface.idl

package FileIface

interface {

Open(in array<UInt8, 1024> path);

Read(out sequence<UInt8, 2048> content);

}

Инициализация IPC-транспорта для межпроцессного взаимодействия

Чтобы инициализировать IPC-транспорт для взаимодействия с другими процессами, нужно вызвать функцию NkKosTransport_Init() или NkKosTransportSync_Init(), объявленные в заголовочном файле transport-kos.h.

Пример использования функции NkKosTransport_Init() на стороне клиента:

int main(int argc, const char *argv[])

{

/* Объявить структуру с параметрами IPC-транспорта */

NkKosTransport driver_transport;

/* Объявить прокси-объект. (Тип прокси-объекта является автоматически

* сгенерированным транспортным кодом.) */

struct FileIface_proxy file_operations_proxy;

/* Объявить структуры для сохранения фиксированной части IPC-запроса и

* IPC-ответа для метода службы. (Типы структур являются автоматически

* сгенерированным транспортным кодом.) */

struct FileIface_Open_req req;

struct FileIface_Open_res res;

...

Retcode rc = rcOk;

Handle selfHandle = INVALID_HANDLE;

Handle serverHandle = INVALID_HANDLE;

Handle callableHandle = INVALID_HANDLE;

DcmHandle subscrHandle = DCM_INVALID_HANDLE;

DcmHandle connectHandle = DCM_INVALID_HANDLE;

KosTask *self = RTL_NULL;

nk_handle_desc_t desc = nk_handle_desc();

char nodeName[UCORE_STRING_SIZE];

DcmPublicationStatus status;

/* Создать подключение к DCM */

rc = DcmInit();

if (rc != rcOk)

{

return rc;

}

/* Получить дескриптор клиентского процесса */

self = KosTaskGetSelf();

if (self != RTL_NULL)

{

selfHandle = KosTaskGetHandle(self);

KosTaskPut(self);

}

/* Создать DCM-дескриптор, позволяющий получать

* уведомления о публикации и отмене публикации служб */

rc = DcmSubscribeToEndpoints(

"FileIface",

RTL_NULL,

RTL_NULL,

INVALID_HANDLE,

selfHandle,

&subscrHandle);

if (rc != rcOk)

{

return rc;

}

/* Извлечь уведомление о публикации службы */

rc = DcmReadPubQueue(

subscrHandle,

TIMEOUT_MSEC,

&serverHandle,

RTL_NULL,

0,

nodeName,

sizeof(nodeName),

&status);

if ((rc != rcOk) || (status != DcmNodePublished))

{

DcmCloseHandle(subscrHandle);

return rc;

}

/* Создать DCM-дескриптор, позволяющий выполнить запрос на создание

* IPC-канала с сервером */

rc = DcmCreateConnection(

"FileIface", nodeName, serverHandle, selfHandle, &connectHandle);

if (rc != rcOk)

{

DcmCloseHandle(subscrHandle);

KnHandleClose(serverHandle);

return rc;

}

/* Выполнить запрос на создание IPC-канала с сервером */

rc = DcmConnectToEndpoint(connectHandle, TIMEOUT_MSEC, &desc);

if (rc != rcOk)

{

DcmCloseHandle(subscrHandle);

DcmCloseHandle(connectHandle);

KnHandleClose(serverHandle);

return rc;

}

DcmCloseHandle(subscrHandle);

DcmCloseHandle(connectHandle);

KnHandleClose(serverHandle);

/* Удалить подключение к DCM */

DcmFini();

/* Получить callable-дескриптор */

callableHandle = nk_get_handle(&desc);

/* Инициализировать структуру с параметрами IPC-транспорта */

NkKosTransport_Init(&driver_transport, callableHandle, NK_NULL, 0);

/* Инициализировать прокси-объект. (Метод инициализации прокси-объекта

* является автоматически сгенерированным транспортным кодом.) */

FileIface_proxy_init(

&file_operations_proxy,

&driver_transport.base,

INVALID_RIID);

...

/* Вызвать метод службы. (Метод является автоматически

* сгенерированным транспортным кодом.) */

strncpy(req.path, "/example/file/path", sizeof(req.path));

if (FileIface_Open(file_operations_proxy.base, &req, RTL_NULL,

&res, RTL_NULL) != NK_EOK) {

...

}

...

}

Если клиенту требуется использовать несколько служб, то нужно инициализировать столько же прокси-объектов. При инициализации каждого прокси-объекта нужно указать IPC-транспорт, ассоциированный через клиентский IPC-дескриптор с нужным сервером. При инициализации нескольких прокси-объектов, относящихся к службам одного сервера, можно указать один и тот же IPC-транспорт, который ассоциирован с этим сервером.

Пример использования функции NkKosTransport_Init() на стороне сервера:

int main(int argc, const char *argv[])

{

/* Объявить структуру с параметрами IPC-транспорта */

NkKosTransport transport;

...

Retcode rc = rcOk;

Handle listenerHandle = INVALID_HANDLE;

Handle callableHandle = INVALID_HANDLE;

Handle selfHandle = INVALID_HANDLE;

DcmHandle pubHandle = DCM_INVALID_HANDLE;

DcmHandle connectHandle = DCM_INVALID_HANDLE;

KosTask *self = RTL_NULL;

char clientName[UCORE_STRING_SIZE];

/* Создать подключение к DCM */

rc = DcmInit();

if (rc != rcOk)

{

return rc;

}

/* Получить дескриптор серверного процесса */

self = KosTaskGetSelf();

if (self != RTL_NULL)

{

selfHandle = KosTaskGetHandle(self);

KosTaskPut(self);

}

/* Опубликовать службу в DCM */

rc = DcmPublishEndpoint(

"FileIface",

"operationsComp.fileOperations",

selfHandle,

&pubHandle);

if (rc != rcOk)

{

return rc;

}

/* Создать слушающий дескриптор */

rc = KnHandleCreateListener(&listenerHandle);

if (rc != rcOk)

{

DcmCloseHandle(pubHandle);

return rc;

}

/* Создать callable-дескриптор. (Идентификатор службы

* FsDriver_operationsComp_fileOperations_iid является

* автоматически сгенерированным транспортным кодом.) */

rc = KnHandleCreateUserObjectEx(

HANDLE_TYPE_USER_FIRST,

OCAP_IPC_CALL | OCAP_HANDLE_TRANSFER,

RTL_NULL,

listenerHandle,

FsDriver_operationsComp_fileOperations_iid,

&callableHandle);

if (rc != rcOk)

{

DcmCloseHandle(pubHandle);

KnHandleClose(listenerHandle);

return rc;

}

/* Получить запрос клиента на создание IPC-канала */

rc = DcmListen(

pubHandle,

INFINITE_TIMEOUT,

&connectHandle,

RTL_NULL,

clientName,

sizeof(clientName));

if (rc != rcOk)

{

KnHandleClose(callableHandle);

KnHandleClose(listenerHandle);

DcmCloseHandle(pubHandle);

return rc;

}

/* Принять запрос клиента на создание IPC-канала */

rc = DcmAcceptEndpointConnection(

connectHandle,

nk_handle_desc(callableHandle, NK_SAME));

if (rc != rcOk)

{

KnHandleClose(callableHandle);

KnHandleClose(listenerHandle);

DcmCloseHandle(pubHandle);

DcmCloseHandle(connectHandle);

return rc;

}

KnHandleClose(callableHandle);

DcmCloseHandle(pubHandle);

DcmCloseHandle(connectHandle);

/* Удалить подключение к DCM */

DcmFini();

/* Инициализировать структуру с параметрами IPC-транспорта */

NkKosTransport_Init(&transport, listenerHandle, NK_NULL, 0);

...

/* Цикл обработки IPC-запросов */

do

{

...

/* Получить IPC-запрос */

rc = nk_transport_recv(&transport.base, ...);

if (rc == NK_EOK) {

/* Обработать IPC-запрос вызовом диспетчера. (Диспетчер

* является автоматически сгенерированным транспортным

* кодом.) */

rc = FsDriver_entity_dispatch(...);

if (rc == NK_EOK) {

/* Отправить IPC-ответ */

rc = nk_transport_reply(&transport.base, ...);

}

}

}

while (rc == NK_EOK)

KnHandleClose(listenerHandle);

return EXIT_SUCCESS;

}

Если сервер обрабатывает IPC-запросы, поступающие через несколько IPC-каналов, то нужно учитывать следующие особенности:

  • Если слушающий дескриптор ассоциирован со всеми IPC-каналами, то для IPC-взаимодействия со всеми клиентами можно использовать один IPC-транспорт, ассоциированный с этим слушающим дескриптором.
  • Если IPC-каналы ассоциированы с разными слушающими дескрипторами, то для IPC-взаимодействия с каждой группой клиентов, соответствующих одному слушающему дескриптору, нужно использовать отдельный IPC-транспорт, ассоциированный с этим слушающим дескриптором. При этом обработку IPC-запросов можно выполнять в параллельных потоках исполнения, если реализация методов служб потокобезопасна.

Функция NkKosTransportSync_Init() позволяет инициализировать IPC-транспорт с поддержкой прерывания блокирующих системных вызовов Call() и Recv(). (Прерывание этих вызовов может потребоваться, например, чтобы корректно завершить процесс, который их выполняет.) Чтобы прерывать системные вызовы Call() и Recv(), нужно использовать API ipc_api.h.

Функция NkKosSetTransportTimeouts(), объявленная в заголовочном файле transport-kos.h, позволяет задать для IPC-транспорта максимальное время блокировки системных вызовов Call() и Recv().

Запуск цикла обработки IPC-запросов

Цикл обработки IPC-запроса на сервере включает следующие стадии:

  1. Получение IPC-запроса.
  2. Обработка IPC-запроса.
  3. Отправка IPC-ответа.

Каждую стадию этого цикла можно выполнять отдельно, последовательно вызывая функции nk_transport_recv(), диспетчер, nk_transport_reply(). (Функции nk_transport_recv() и nk_transport_reply() объявлены в заголовочном файле sysroot-*-kos/include/nk/transport.h из состава KasperskyOS SDK.) А можно вызвать функцию NkKosTransport_Dispatch(), NkKosDoDispatch() или NkKosDoDispatchEx(), внутри которых этот цикл выполняется полностью. (Функция NkKosTransport_Dispatch() объявлена в заголовочном файле transport-kos.h, функции NkKosDoDispatch() и NkKosDoDispatchEx() объявлены в заголовочном файле transport-kos-dispatch.h.) Использовать функцию NkKosDoDispatch() или NkKosDoDispatchEx() удобнее по сравнению с функцией NkKosTransport_Dispatch(), поскольку нужно выполнять меньше подготовительных операций (в том числе не требуется инициализировать IPC-транспорт).

Для инициализации структуры, передаваемой функции NkKosDoDispatch() или NkKosDoDispatchEx() через параметр info, можно использовать макросы, определенные в заголовочном файле transport-kos-dispatch.h. Используя параметр syncHandle функции NkKosDoDispatchEx(), можно прерывать системный вызов Recv() с целью выхода из цикла обработки IPC-запросов. Через параметр cb функции NkKosDoDispatchEx() можно задать callback-функции, вызываемые после выполнения системных вызовов Recv() и Reply(), а также после выхода из цикла обработки IPC-запросов (все функции задавать не требуется). Callback-функция, соответствующая указателю enterDispatchProcessing, вызывается сразу после выполнения системного вызова Recv(). Callback-функция, соответствующая указателю leaveDispatchProcessing, вызывается сразу после выполнения системного вызова Reply(). Callback-функция, соответствующая указателю stopDispatchLoop, вызывается сразу после выхода из цикла обработки IPC-запросов. Каждой из этих callback-функций передается указатель callbackContext. Эти callback-функции используются, например, в реализации пула потоков исполнения для обработки IPC-запросов.

Функции NkKosTransport_Dispatch(), NkKosDoDispatch() и NkKosDoDispatchEx() можно вызывать из параллельных потоков исполнения, если реализация методов служб потокобезопасна.

Пример использования функции NkKosDoDispatch():

/* Функция реализует метод службы. */

static nk_err_t Open_impl(...)

{

...

}

/* Функция реализует метод службы. */

static nk_err_t Read_impl(...)

{

...

}

/* Функция инициализирует указатели на функции, реализующие методы службы.

* (Эти указатели используются диспетчером для вызова функций, реализующих

* методы службы. Типы структур являются автоматически сгенерированным

* транспортным кодом.) */

static struct FileIface *CreateFileOperations()

{

static const struct FileIface_ops ops = {

.Open = Open_impl,

.Read = Read_impl

};

static struct FileIface impl = {

.ops = &ops

};

return &impl;

}

int main(int argc, const char *argv[])

{

/* Объявить стабы. (Типы стабов являются автоматически сгенерированным

* транспортным кодом. */

struct Operations_component component;

struct FsDriver_entity entity;

...

/* Получить слушающий дескриптор */

Handle handle = SLStaticResolveHandle("driver_connection", HandleTypeServer);

assert(handle != INVALID_HANDLE);

/* Инициализировать стабы. (Методы инициализации стабов являются

* автоматически сгенерированным транспортным кодом. Функция

* CreateFileOperations() реализована разработчиком решения на

* базе KasperskyOS, чтобы инициализировать

* указатели на функции, реализующие методы службы.) */

Operations_component_init(&component, CreateFileOperations());

FsDriver_entity_init(&entity, &component);

/* Инициализировать структуру, которая требуется функции

* NkKosDoDispatch() для использования транспортного кода. */

NkKosDispatchInfo info = NK_TASK_DISPATCH_INFO_INITIALIZER(FsDriver, entity);

/* Запустить цикл обработки IPC-запросов */

NkKosDoDispatch(handle, &info);

return EXIT_SUCCESS;

}

Пример использования функции NkKosTransport_Dispatch():

/* Функция реализует метод службы. */

static nk_err_t Open_impl(...)

{

...

}

/* Функция реализует метод службы. */

static nk_err_t Read_impl(...)

{

...

}

/* Функция инициализирует указатели на функции, реализующие методы службы.

* (Эти указатели используются диспетчером для вызова функций, реализующих

* методы службы. Типы структур являются автоматически сгенерированным

* транспортным кодом.) */

static struct FileIface *CreateFileOperations()

{

static const struct FileIface_ops ops = {

.Open = Open_impl,

.Read = Read_impl

};

static struct FileIface impl = {

.ops = &ops

};

return &impl;

}

int main(int argc, const char *argv[])

{

/* Объявить структуру с параметрами IPC-транспорта */

NkKosTransport transport;

/* Объявить стабы. (Типы стабов являются автоматически сгенерированным

* транспортным кодом. */

struct Operations_component component;

struct FsDriver_entity entity;

/* Объявить объединения фиксированной части IPC-запросов и

* IPC-ответов. (Типы объединений являются автоматически сгенерированным

* транспортным кодом.) */

union FsDriver_entity_req req;

union FsDriver_entity_res res;

/* Объявить массив для арены IPC-ответов. (Размер массива является

* автоматически сгенерированным транспортным кодом.) */

char res_buffer[FsDriver_entity_res_arena_size];

/* Объявить и инициализировать дескриптор арены IPC-ответов.

* (Тип дескриптора и макрос его инициализации определены в заголовочном файле

* sysroot-*-kos/include/nk/arena.h из состава KasperskyOS SDK.) */

struct nk_arena res_arena = NK_ARENA_INITIALIZER(res_buffer,

res_buffer + sizeof(res_buffer));

...

/* Получить слушающий дескриптор */

Handle handle = SLStaticResolveHandle("driver_connection", HandleTypeServer);

assert(handle != INVALID_HANDLE);

/* Инициализировать структуру с параметрами IPC-транспорта */

NkKosTransport_Init(&transport, handle, NK_NULL, 0);

/* Инициализировать стабы. (Методы инициализации стабов являются

* автоматически сгенерированным транспортным кодом. Функция

* CreateFileOperations() реализована разработчиком решения на

* базе KasperskyOS, чтобы инициализировать

* указатели на функции, реализующие методы службы.) */

Operations_component_init(&component, CreateFileOperations());

FsDriver_entity_init(&entity, &component);

/* Запустить цикл обработки IPC-запросов. (Диспетчер FsDriver_entity_dispatch

* является автоматически сгенерированным транспортным кодом.) */

NkKosTransport_Dispatch(&transport.base, FsDriver_entity_dispatch,

&entity, &req, sizeof(FsDriver_entity_req),

RTL_NULL, &res, &res_arena);

return EXIT_SUCCESS;

}

Копирование данных в арену IPC-сообщений

Чтобы скопировать строку в арену IPC-сообщений, нужно вызвать функцию NkKosCopyStringToArena(), объявленную в заголовочном файле transport-kos.h. Эта функция резервирует участок арены и копирует строку в этот участок.

Пример использования функции NkKosCopyStringToArena():

static nk_err_t Read_impl(struct FileIface *self,

const struct FileIface_Read_req *req,

const struct nk_arena* req_arena,

struct FileIface_Read_res* res,

struct nk_arena* res_arena)

{

/* Скопировать строку в арену IPC-ответов */

if (NkKosCopyStringToArena(res_arena, &res->content,

"CONTENT OF THE FILE") != rcOk) {

...

}

return NK_EOK;

}

Сведения о функциях API

Функции transport-kos.h

Функции transport-kos-dispatch.h

Вам помогла эта статья?
Что нам нужно улучшить?
Спасибо за ваш отзыв, вы помогаете нам становиться лучше!
Спасибо за ваш отзыв, вы помогаете нам становиться лучше!