Динамическое создание IPC-каналов при разработке на языке C++

Динамическое создание IPC-канала на стороне клиента включает следующие шаги:

  1. Подключить к клиентской программе сгенерированный заголовочный файл описания (*.edl.cpp.h).
  2. Подключить сгенерированные заголовочные файлы описаний используемых интерфейсов (*.idl.cpp.h).
  3. Подключить заголовочные файлы:
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/application.h
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/make_application.h
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/connect_dynamic_channel.h
  4. Получить указатели на имя сервера и квалифицированное имя службы с помощью сервера имен – специального сервиса ядра, представленного программой NameServer. Для этого необходимо подключиться к серверу имен вызовом функции NsCreate() и найти сервер, предоставляющий требуемую службу, используя функцию NsEnumServices(). Подробнее см. "Динамическое создание IPC-каналов (cm_api.h, ns_api.h)".
  5. Создать объект приложения, вызвав функцию kosipc::MakeApplicationAutodetect(). (Также можно использовать функции kosipc::MakeApplication() и kosipc::MakeApplicationPureClient().)
  6. Создать прокси-объект для требуемой службы, вызвав функцию MakeProxy(). В качестве входного параметра функции MakeProxy() использовать вызов функции kosipc::ConnectDynamicChannel(). В функцию kosipc::ConnectDynamicChannel() передать указатели на имя сервера и квалифицированное имя службы, полученные на шаге 4.

После успешной инициализации прокси-объекта клиенту доступен вызов методов требуемой службы.

Пример

NsHandle ns;

// Подключение к серверу имен

Retcode rc = NsCreate(RTL_NULL, INFINITE_TIMEOUT, &ns);

char serverName[kl_core_Types_UCoreStringSize];

char endpointName[kl_core_Types_UCoreStringSize];

// Получение указателей на имя сервера и квалифицированное имя службы

rc = NsEnumServices(

ns, interfaceName, 0,

serverName, kl_core_Types_UCoreStringSize,

endpointName, kl_core_Types_UCoreStringSize);

// Создание и инициализация объекта приложения

kosipc::Application app = kosipc::MakeApplicationAutodetect();

// Создание и инициализация прокси-объекта

auto proxy = app.MakeProxy<IDLInterface>(

kosipc::ConnectDynamicChannel(serverName, endpointName))

// Вызов метода требуемой службы

proxy->DoSomeWork();

Динамическое создание IPC-канала на стороне сервера включает следующие шаги:

  1. Подключить к серверной программе сгенерированный заголовочный файл (*.edl.cpp.h), содержащий описание компонентной структуры сервера, включая все предоставляемые службы.
  2. Подключить заголовочные файлы:
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/application.h
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/event_loop.h
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/make_application.h
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/root_component.h
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/serve_dynamic_channel.h
    • /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/simple_connection_acceptor.h
  3. Создать классы, содержащие реализации интерфейсов, которые сервер предоставляет в виде служб. Создать и инициализировать объекты этих классов.
  4. Создать объект приложения, вызвав функцию kosipc::MakeApplicationAutodetect().
  5. Создать и инициализировать объект класса kosipc::components::Root, который описывает структуру компонентов и служб сервера. Эта структура генерируется из описаний в CDL- и EDL-файлах.
  6. Cвязать объект класса kosipc::components::Root с объектами классов, созданными на шаге 3.
  7. Создать и инициализировать объект класса kosipc::EventLoop, который реализует цикл диспетчеризации входящих IPC-сообщений, вызвав функцию MakeEventLoop(). В качестве входного параметра функции MakeEventLoop() использовать вызов функции ServeDynamicChannel(). В функцию ServeDynamicChannel() передать объект класса kosipc::components::Root, созданный на шаге 5.
  8. Запустить цикл диспетчеризации входящих IPC-сообщений в отдельном потоке, вызвав метод Run() объекта kosipc::EventLoop.
  9. Создать и инициализировать объект, который реализует обработчик приема входящих запросов на динамическое создание IPC-канала.

    При создании объекта можно использовать класс kosipc::SimpleConnectionAcceptor, который является стандартной реализацией интерфейса kosipc::IConnectionAcceptor. (Интерфейс kosipc::IConnectionAcceptor определен в файле /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/kosipc/connection_acceptor.h.) В этом случае обработчик будет реализовать следующую логику: если запрашиваемая клиентом служба опубликована на сервере, то запрос от клиента будет принят, иначе отклонен.

    Если необходимо создать собственный обработчик, то следует реализовать свою логику обработки запросов в методе OnConnectionRequest(), унаследованном от интерфейса kosipc::IConnectionAcceptor. Этот метод будет вызываться сервером при получении от клиента запроса на динамическое создание IPC-канала.

  10. Создать объект класса kosipc::EventLoop, который реализует цикл приема входящих запросов на динамическое создание IPC-канала, вызвав функцию MakeEventLoop(). В качестве входного параметра функции MakeEventLoop() использовать вызов функции ServeConnectionRequests(). В функцию ServeConnectionRequests() передать объект, созданный на шаге 9.

    Цикл приема входящих запросов на динамическое создание IPC-канала может быть только один. Цикл должен работать в одном потоке. Цикл приема входящих запросов на динамическое создание IPC-канала должен быть создан после создания цикла диспетчеризации входящих IPC-сообщений (см. на шаг 7).

  11. Запустить цикл приема входящих запросов на динамическое соединение в текущем потоке, вызвав метод Run() объекта kosipc::EventLoop.

Пример

// Создание объектов классов, которые реализуют интерфейсы,

// предоставляемые сервером в виде служб

MyIDLInterfaceImp_1 impl_1;

MyIDLInterfaceImp_2 impl_2;

// Создание и инициализация объекта приложения

kosipc::Application app = kosipc::MakeApplicationAutodetect();

// Создание и инициализация объекта root, описывающего

// компоненты и службы сервера

kosipc::components::Root root;

// Связывание объекта root с объектами классов, реализующими службы сервера.

// Поля объекта root повторяют описание компонентов и служб,

// заданную совокупностью CDL- и EDL-файлов.

root.component1.endpoint1 = &impl_1;

root.component2.endpoint2 = &impl_2;

// Создание и инициализация объекта, который реализует

// цикл диспетчеризации входящих IPC-сообщений

kosipc::EventLoop loopDynamicChannel = app.MakeEventLoop(ServeDynamicChannel(root));

// Запуск цикла диспетчеризации входящих IPC-сообщений в отдельном потоке

std::thread dynChannelThread(

[&loopDynamicChannel]() {

loopDynamicChannel.Run();

}

);

// Создание объекта, реализующего стандартный обработчик приема входящих запросов

// на динамическое создание IPC-канала

kosipc::SimpleConnectionAcceptor acceptor(root);

// Создание объекта, реализующего цикл приема входящих запросов

// на динамическое создание IPC-канала

kosipc::EventLoop loopDynamicChannel = app.MakeEventLoop(ServeConnectionRequests(&acceptor));

// Запуск цикла приема входящих запросов на динамическое создание IPC-канала в текущем потоке

loopConnectionReq.Run();

При необходимости можно создать и инициализировать несколько объектов класса kosipc::components::Root, объединенных в список объектов типа ServiceList с помощью метода AddServices(). Использование нескольких объектов позволяет, например, разделять компоненты и службы сервера на группы или публиковать службы под разными именами.

Пример

// Создание и инициализация объекта group_1

kosipc::components::Root group_1;

group_1.component1.endpoint1 = &impl_1;

group_1.component2.endpoint2 = &impl_2;

// Создание и инициализация объекта group_2

kosipc::components::Root group_2;

group_2.component1.endpoint1 = &impl_3;

group_2.component2.endpoint2 = &impl_4;

// Создание и инициализация объекта group_3

kosipc::components::Root group_3;

group_3.component1.endoint1 = &impl_5;

// Создание списка объектов

ServiceList endpoints;

endpoints.AddServices(group_1);

endpoints.AddServices(group_2);

endpoints.AddServices(group_3.component1.endpoint1, "SomeCustomEndpointName");

// Создание объекта, реализующего обработчик приема входящих запросов

// на динамическое создание IPC-канала

kosipc::SimpleConnectionAcceptor acceptor(std::move(endpoints));

// Создание объекта, реализующего цикл приема входящих запросов

// на динамическое создание IPC-канала

kosipc::EventLoop loopDynamicChannel = app.MakeEventLoop(ServeConnectionRequests(&acceptor));

В начало