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

Для динамического создания IPC-каналов при разработке на языке С++ используется системная программа DCM, поставляемая в составе KasperskyOS SDK. API этой программы представлен в разделе "Динамическое создание IPC-каналов с использованием системной программы DCM".

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

  1. Подключить к клиентской программе сгенерированный заголовочный файл описания (*.edl.cpp.h).
  2. Подключить сгенерированные заголовочные файлы описаний используемых интерфейсов (*.idl.cpp.h).
  3. Подключить заголовочные файлы из состава KasperskyOS SDK:
    • /opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/application.h
    • /opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/make_application.h
    • /opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/unique_ptr.h
    • /opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/connect_dcm_publication.h
  4. Создать объект приложения, вызвав функцию kosipc::MakeApplicationAutodetect(). (Также можно использовать функции kosipc::MakeApplication() и kosipc::MakeApplicationPureClient().)
  5. Создать и инициализировать прокси-объект для службы, реализующей требуемый интерфейс:
    • Вызвать функцию MakeProxy<Interface>().
    • В качестве входного параметра функции MakeProxy<Interface>() использовать вызов функции kosipc::ConnectDcmPublication().
    • Передать функции kosipc::ConnectDcmPublication() в качестве параметров:
      1. [Опционально] имя сервера или std::nullopt, чтобы получаемые уведомления о публикации службы на сервере не фильтровались по имени сервера.
      2. [Опционально] квалифицированное имя службы или std::nullopt, чтобы получаемые уведомления о публикации службы на сервере не фильтровались по квалифицированному имени службы.
      3. [Опционально] дескриптор, идентифицирующий сервер, или std::nullopt, чтобы получаемые уведомления о публикации службы на сервере не фильтровались по конкретному серверу.
      4. [Опционально] время ожидания поиска службы или std::nullopt, чтобы задать неограниченное время ожидания. Значение по умолчанию: std::nullopt.
      5. [Опционально] время ожидания ответа сервера на запрос соединения или std::nullopt, чтобы задать неограниченное время ожидания. Значение по умолчанию: std::nullopt.

      Если ни один из параметров не указан, функция kosipc::ConnectDcmPublication() будет пытаться установить соединение с первой доступной на сервере службой, реализующей требуемый интерфейс.

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

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

Пример

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

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

// Создание прокси-объекта для службы, реализующей интерфейс Writer.

// Функция kosipc::ConnectDcmPublication() установит соединение с первой

// доступной на сервере службой, реализующей требуемый интерфейс.

// Время ожидания поиска службы ограничено таймаутом в 10 минут.

auto writer = app.MakeProxy<Writer>(kosipc::ConnectDcmPublication(10min));

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

writer->DoSomeWork();

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

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

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

    Библиотека kosipc обеспечивает гарантию: при создании объекта класса kosipc::DcmServicePublisher все переданные ему службы публикуются в DCM, а при разрушении объекта – снимаются с публикации.

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

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

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

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

    После создания и запуска циклов не требуется синхронизации между потоками, в которых циклы исполняются.

  12. Запустить цикл диспетчеризации входящих IPC-сообщений в отдельном потоке, вызвав метод Run() объекта kosipc::EventLoop.
  13. Запустить в текущем потоке цикл приема входящих запросов на динамическое создание IPC-канала, вызвав метод Run() объекта kosipc::EventLoop. До запуска этого цикла клиентские процессы блокируются при создании прокси-объекта в ожидании ответа от сервера на запрос подключения.

Пример кода для объединения набора компонентов и служб сервера в список объектов типа ServiceList с помощью метода AddServices():

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

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

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

kosipc::components::Root group_1;

group_1.component1.endpoint1 = &impl_1;

group_1.component2.endpoint2 = &impl_2;

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

kosipc::EventLoop loop1 = app.MakeEventLoop(ServeDynamicChannel(group_1));

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

kosipc::components::Root group_2;

group_2.component3.endpoint1 = &impl_3;

group_2.component4.endpoint2 = &impl_4;

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

kosipc::EventLoop loop2 = app.MakeEventLoop(ServeDynamicChannel(group_2));

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

kosipc::components::Root group_3;

group_3.component5.endpoint1 = &impl_5;

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

kosipc::EventLoop loop3 = app.MakeEventLoop(ServeDynamicChannel(group_3));

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

ServiceList endpoints;

endpoints.AddServices(group_1);

endpoints.AddServices(group_2);

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

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

kosipc::DcmServicePublisher publisher(app, endpoints);

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

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

kosipc::SimpleConnectionAcceptor acceptor(app, endpoints);

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

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

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

В начало