Dynamically creating IPC channels for C++ development using NameServer

Use of the NameServer system program to dynamically create IPC channels is outdated and therefore inadvisable. Instead, you must use the DCM system program to create them (see Dynamically creating IPC channels for C++ development using DCM).

Dynamic creation of an IPC channel on the client side includes the following steps:

  1. Include the generated description header file (*.edl.cpp.h) in the client program.
  2. Include the generated header files of the descriptions of the utilized interfaces (*.idl.cpp.h).
  3. Include the header files from the 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/connect_dynamic_channel.h
  4. Create an application object by calling the kosipc::MakeApplicationAutodetect() function. (You can also use the kosipc::MakeApplication() and kosipc::MakeApplicationPureClient() functions.)
  5. Create and initialize the proxy object for the endpoint that implements the required interface. You can use a name server (the NameServer system program) to get a full list of endpoints with the required interface. For more details, refer to Dynamically creating IPC channels (cm_api.h, ns_api.h).
    • Create a proxy object for the endpoint that implements the required interface and is found first among the endpoints published on the name server.
      1. Call the MakeProxy() function.
      2. Use the kosipc::ConnectPublishedService() function call as the input parameter of the MakeProxy() function.
      3. Pass the pointer for the endpoint interface name to the kosipc::ConnectPublishedService() function.
    • Create the proxy object for any endpoint in the list of endpoints that implement the required interface and are published on the name server.
      1. Connect to the name server by calling the NsCreate() function.
      2. Get the full list of endpoints that implement the required interface and are published on the name server by using the NsEnumServices() function in a loop. For each endpoint in this list, the NsEnumServices() function returns the pointer to the server name (the server parameter) and the pointer to the qualified name of the endpoint (the service parameter).
      3. From the list obtained in the previous step, select an endpoint according to the logic of the solution being developed.
      4. Call the MakeProxy() function.
      5. Use the kosipc::ConnectDynamicChannel() function call as the input parameter of the MakeProxy() function.
      6. Pass the pointers to the server name and qualified endpoint name obtained at step b in the current list to the kosipc::ConnectDynamicChannel() function.

After successful initialization of the proxy object, the client can call endpoint methods.

Example

NsHandle ns;

// Connect to a name server

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

char serverName[kl_core_Types_UCoreStringSize];

char endpointName[kl_core_Types_UCoreStringSize];

// Get pointers to the server name and qualified name of the endpoint

rc = NsEnumServices(

ns, interfaceName, 0,

serverName, kl_core_Types_UCoreStringSize,

endpointName, kl_core_Types_UCoreStringSize);

// Create and initialize the application object

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

// Create and initialize the proxy object

auto proxy = app.MakeProxy<Writer>(

kosipc::ConnectDynamicChannel(serverName, endpointName))

// Call the method of the required endpoint

writer->DoSomeWork();

Dynamic creation of an IPC channel on the server side includes the following steps:

  1. Include the generated header file (*.edl.cpp.h) containing a description of the component structure of the server, including all provided endpoints, in the server program.
  2. Include the header files from the 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/ns_service_publisher.h>
  3. Create classes containing the implementations of interfaces that the server provides as endpoints. Create and initialize the objects of these classes.
  4. Create an application object by calling the kosipc::MakeApplicationAutodetect() function.
  5. Create and initialize the kosipc::components::Root class object that describes the structure of components and endpoints of the server. This structure is generated from the descriptions in the CDL and EDL files.
  6. Bind the kosipc::components::Root class object to the class objects created at step 3.
  7. Create and initialize the kosipc::EventLoop class object that implements a loop for dispatching incoming IPC messages by calling the MakeEventLoop() function. Use the ServeDynamicChannel() function call as an input parameter of the MakeEventLoop() function. Pass the kosipc::components::Root class object created at step 5 to the ServeDynamicChannel() function.
  8. [Optional] Create and initialize an object of the kosipc::ServiceList class that contains a list of endpoints to be published on the server. To add endpoints to the list, use the AddServices() method. For example, use of an object of the kosipc::ServiceList class enables you to separate components and endpoints of the server into groups or publish endpoints under different names (see below for a code example).
  9. Create and initialize an object of the kosipc::NsServicePublisher class that is intended for publishing endpoints on the server. Pass the following input parameters to the constructor:
    • Application object from step 4.
    • Object of the kosipc::components::Root class created at step 5, or the kosipc::ServiceList class object generated at step 8.

    If you do not need to publish endpoints on the name server, create and initialize the kosipc::CmServicePublisher class object (empty publisher). Pass the following input parameters to the constructor:

    • Application object from step 4.
    • Object of the kosipc::components::Root class created at step 5, or the kosipc::ServiceList class object generated at step 8.

    The objects created at steps 9-11 must be created after the loop for dispatching incoming IPC messages is created (see step 7).

    The kosipc library guarantees the following: when an object of the kosipc::NsServicePublisher class is created, all endpoints passed to it are published on the name server, and they are unpublished when the object is destroyed.

  10. Create and initialize the object that implements the handler for receiving incoming requests to dynamically create an IPC channel.

    When creating an object, you can use the kosipc::SimpleConnectionAcceptor class, which is the standard implementation of the kosipc::IConnectionAcceptor interface. (The kosipc::IConnectionAcceptor interface is defined in the file named /opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/connection_acceptor.h.) In this case, the handler will implement the following logic: if the endpoint requested by the client was published on the server, the request from the client will be accepted. Otherwise, it will be rejected.

    If you need to create your own handler, you should implement your own request handling logic in the OnConnectionRequest() method inherited from the kosipc::IConnectionAcceptor interface. This method will be called by the server when it receives a request for dynamic IPC channel creation from the client.

  11. Create a kosipc::EventLoop class object that implements a loop for receiving incoming requests to dynamically create an IPC channel by calling the MakeEventLoop() function. Use the ServeConnectionRequests() function call as an input parameter of the MakeEventLoop() function. Pass the objects created at step 9 and 10 to the ServeConnectionRequests() function. Objects can be passed using smart pointers (std::shared_ptr) or ordinary pointers. In the first case, the kosipc library takes control of the lifetime of objects. In the second case, the responsibility remains with the developer to ensure that the objects created at steps 9 and 10 are not destroyed before the kosipc::EventLoop object finishes.

    There can only be one loop for receiving incoming requests to dynamically create an IPC channel. The loop must work in one thread. After creating and starting loops, there is no need for synchronization between threads in which the loops are executed.

  12. Start the loop for dispatching incoming IPC messages in a separate thread by calling the Run() method of the kosipc::EventLoop object.
  13. In the current thread, start the loop for receiving incoming requests for a dynamic IPC channel connection by calling the Run() method of the kosipc::EventLoop object. Prior to starting this loop, client processes are locked when a proxy object is created while waiting for the server to respond to the connection request.

Example code for combining the set of components and endpoints of the server into a list of ServiceList-type objects using the AddServices() method:

// Create an application object

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

// Create and initialize the group_1 object

kosipc::components::Root group_1;

group_1.component1.endpoint1 = &impl_1;

group_1.component2.endpoint2 = &impl_2;

// Create a loop for dispatching incoming IPC messages

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

// Create and initialize the group_2 object

kosipc::components::Root group_2;

group_2.component3.endpoint1 = &impl_3;

group_2.component4.endpoint2 = &impl_4;

// Create a loop for dispatching incoming IPC messages

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

// Create and initialize the group_3 object

kosipc::components::Root group_3;

group_3.component5.endpoint1 = &impl_5;

// Create a loop for dispatching incoming IPC messages

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

// Create a list of objects

ServiceList endpoints;

endpoints.AddServices(group_1);

endpoints.AddServices(group_2);

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

// Create an object that implements publication of endpoints on the server

kosipc::NsServicePublisher publisher(app, endpoints);

// Create an object that implements the handler for receiving incoming requests

// to dynamically create an IPC channel

kosipc::SimpleConnectionAcceptor acceptor(app, endpoints);

// Create an object that implements a loop for receiving incoming requests

// to dynamically create an IPC channel

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

Page top