################## C++ API Reference ################## The C++ API is mainly a convenience wrapper around the C Interface, which provides the implementation. In case that you need more details, links to the C counter parts are provided where useful. .. highlight:: cpp .. default-domain:: cpp .. _reference/cpp/header: Required Headers ================ To use the LN C++ client library, you have to include its headers into your C++ source file like this: .. sourcecode:: c++ #include .. index:: pair: thread safety; C++ API Thread-Safety ============= The API functions can be classified into two categories: * Functions and constructors which set up connections and configure the client, like the :cpp:class:`ln::client` constructor, or the :cpp:func:`ln::client::subscribe()` method. * Functions and constructors which do communication. The first group of functions should only be used in a single thread. The second group of functions can be used from multiple threads and are thread-safe. Exception Safety ================ Objects which are created by the API are exception-safe and do not need to be deallocated or fixed up when handling exceptions. If pointers to API objects are returned (for example, by :cpp:func:`ln::client::subscribe()`), these are always non-owning instances. Objects such as port objects should never be used longer when the life time of the corresponding :cpp:class:`ln::client` object or the objects which were used to create them ends. .. index:: pair: C++ API; fork() calls fork() calls ============ The ``fork()`` system call is not supported by the LN library. This means that ``fork()`` should not be called when any LN client instance is active. Otherwise, strange things can happen (for example, the LN manager might become confused about the identity of clients and their state). Main API functions ================== .. _reference/cpp/placeholders: Placeholders used in this description ------------------------------------- For C++, a number of API functions are auto-generated by the :program:`ln_generate` command, so that they have names generated from message definitions. Here, these names are placed in meta-variable brackets, like so: ````. .. seealso:: :ref:`User guide section on ln_generate ` To understand their meaning better, it can help to compare the descriptions provided here to the symbols used in :doc:`tutorial_cpp`. The correspondence of the placeholders used here, and the symbols there is as follows: ===================================== ========================================================================= Placeholder in the Reference below Name in Tutorial Example ===================================== ========================================================================= **TOPIC_PREFIX** := "elevator03" **TOPIC_SUFFIX** := one of "sensors", "actors", or "prompt" **MESSAGE_DEF_NAMESPACE** := one of "elevator/sensors", "elevator/actors", or "elevator/request" **MDEF_NAME** := one of "floor_count", "motor_control", or "elevator_call" **SVMDEF_NAME** := "elevator_call" **CLIENT_CLASS** := "ElevatorClient" **PROVIDER_CLASS** := "ElevatorServer" ===================================== ========================================================================= It is important to realize that the names of message definitions and the names of topics or services are completely orthogonal - they can be the same, but they do not have to be the same. This is because they serve different purposes: message definitions describe a (possibly general) *type* of data, and the topics or services describe data streams or command connections within a specific system. .. _reference/cpp/client_class: Client class ------------ .. _reference/cpp/client_class/constructor: .. rubric:: Constructor .. cpp:class:: ln::client .. cpp:function:: client(std::string client_name) .. cpp:function:: client(std::string client_name, int argc, char* argv[]) .. cpp:function:: client(std::string client_name, std::string ln_manager) .. cpp:function:: client(ln::client clnt) An LN client instance which holds information on the connection. Tries to TCP-connect to the ln-manager on construction. *client_name* should be a string to help identify this client within the ln-manager. This suggestion will be ignored when the :envvar:`LN_PROGRAM_NAME` environment variable var is set, which will take precedence and will be used used instead in this case. **Attention:** The suggested name is only used if no other client instance with that name is already running. The exact behavior is described in :ref:`guide/concepts/clients/client-names` if *argc* and *argv* are set, this are assumed to be command line parameters passed from ``main()``, which will contain instance parameters for contacting the LN manager. if *ln_manager* is a string, it is set in the form ``HOST:PORT`` of the ln-managers TCP-address. Additionally, the client will read the ln-manager address from the :envvar:`LN_MANAGER` environment variable. This will take precedence over any settings via the constructor parameters. The constructor can throw an exception if type `exception` with an error message in the case of run-time errors (such as a wrong address or a failure to create a connection) or an unimplemented configuration. (For details on errors, please see :c:type:`ln_client` in the C API reference.) .. seealso:: * :c:type:`ln_client` in the C API * :c:func:`ln_init()` in the C API * :c:func:`ln_init_to_manager()` in the C API * :c:type:`ln_client` in the C API * :py:class:`client` in the Python API Client Instance Methods ^^^^^^^^^^^^^^^^^^^^^^^ .. cpp:function:: ln::outport* ln::client::publish(std::string topic_name, \ std::string message_def_name, unsigned int buffers=1) Create an :class:`outport` for a specific topic and message definition. *topic_name* Is the name of the :ref:`topic ` for which the data is published. The name can be grouped into name spaces, which are separated with a dot ("."). The topic name must not end with a leading slash or dot. For a more detailed specification, see :ref:`guide/rules_for_topic_names`. *message_definition_name* The name if the :term:`message definition` to use (see :ref:`the tutorial introduction on message-passing ` for more information). This is a full path name for the file with the message definition, separated by forward slashes ("/"). The same separator is used on non-Unix systems. The message definition is searched along the search path defined in :envvar:`LN_MESSAGE_DEFINITION_DIRS`. .. tip:: See :ref:`the tutorial ` for more information on message definitions. A short summary in :ref:`tutorial/python/summary_api/message-definitions` in the :doc:`tutorial_python` chapter. For more detailed information, see ref:`guide/message_definitions` in the user guide. For detailed information on setting the message definition search path, see section :envvar:`LN_MESSAGE_DEFINITION_DIRS` in the reference part. *buffers* is the number of buffers to use. The default value is 1. If data is lost, set it to a higher value. .. warning:: The resources of the outport handle are owned and handled by the client instance. The :term:`life time` of the handle is limited to the life time of the client instance; it cannot be used longer when the client instance get destroyed. .. seealso:: * :cpp:func:`client::publish` in the C++ API * :c:func:`ln_publish` (C API) * :c:func:`ln_unpublish` (C API) .. cpp:function:: ln::inport* ln::client::subscribe(std::string topic_name, std::string message_def_name, \ double rate=-1, unsigned int buffers=1, bool need_reliable_transport=false) Subscribe to named topic and returns an instance of :py:class:`inport`. *topic_name* is the name of the :ref:`topic `. The name can be grouped into name spaces, which are separated with a dot ("."). The topic name must not end with a leading slash or dot. For a more detailed specification, see :ref:`guide/rules_for_topic_names`. *message_definition_name* is the name of the :term:`message definition` to use, as a path name from the message-definition folder to the message definition file, separated by slashes ("\"). If *message_definition_name* is ``None`` and the topic is already published, the message definition name will be retrieved from the ln-manager. *rate* is a limit which specifies the maximum sending-rate in messages per second. With the default of ``-1`` the topic will be subscribed without :term:`rate-limiter `, the publisher decides the update-rate. Note that messages exceeding the rate limit will not be seen by the subscriber, even if they were sent correctly. Proper rate-limiting messages requires that the messages which are sent by publishers have the timestamp parameter of the :cpp:func:`ln::port::write()` set in the unit of seconds. *buffers* is the number of message buffers to use. Increasing the number of buffers can prevent problems if a receiver is temporarily delayed, but messages should not be lost. If no empty buffers are available, previous messages are overwritten by new messages (CHECK). The default value is 1; a good value is often 3. If data is lost, set this number to a higher value, or make sure that the receiving process works with minimum :term:`latency` as a :term:`real-time` process. *need_reliable_transport* is of interest when the topic needs to be transported across a network. If set to ``true`` TCP will be used to get a reliable communication channel. Otherwise UDP is used. .. warning:: The resources of the inport handle are owned and handled by the client instance. The :term:`life time` of the handle is limited to the life time of the client instance; it cannot be used longer when the client instance get destroyed. .. tip:: See :ref:`the tutorial ` for more information on message definitions. A short summary in :ref:`tutorial/cpp/summary_api/message-definitions` in the :doc:`tutorial_cpp` chapter. For more detailed information, see ref:`guide/message_definitions` in the user guide. For detailed information on setting the message definition search path, see section :envvar:`LN_MESSAGE_DEFINITION_DIRS` in the reference part. .. note:: If the *message_definition_name* is specified but is unknown to the ln-manager, an :cpp:type:`Exception` exception is raised. .. seealso:: * :c:func:`ln_subscribe` (C API) .. cpp:function:: ln::client::wait_and_handle_service_group_requests(const char* group_name,\ double timeout=-1) Handles all pending service requests for a :term:`service group`. The handlers will all run in the current thread (usually, the main thread), and will not be executed concurrently. This method should be used by default, as it is much safer and simpler than concurrent handling of requests, which is difficult to do correctly. Calling this method is necessary to serve requests. .. note:: Concurrent calls of ``wait_and_handle_service_group_requests()`` for the same service group are serialized internally. This is a safety guard, not a recommended scheduling model. Prefer one dispatcher thread per service group, or use :cpp:func:`ln::client::handle_service_group_in_thread_pool()` when service handlers should run concurrently. *group_name* name of the :term:`service group`. The parameter can be set to nullptr to use a default value. *timeout* The maximum time, in seconds, that the function will wait for requests before returning. This can be used to handle requests to different service groups in quick succession, by handling them sequentially, while not incurring risk that bugs occur because of incorrect locking. .. cpp:function:: ln::client::handle_service_group_in_thread_pool(const char* group_name, \ std::string pool_name) Defines the name of a :term:`service group` and a thread pool for service threads, and starts to handle service requests. This method is an alternative to :cpp:func:`ln::client::wait_and_handle_service_group_requests()`. In difference to the latter, service requests are handled concurrently, which can yield lower latencies or be faster. Important: Any data that is modified during a service request (by the handling thread or by another thread) needs to be protected with mutexes. If in doubt, use always :cpp:func:`ln::client::wait_and_handle_service_group_requests()`, because correct programming in multiple threads is much more difficult and prone to non-deterministic bugs such as :term:`race conditions `, which can cause :term:`undefined behavior`. *group_name* name of the :term:`service group`. This value can be set to ``nullptr``. *pool_name* name of the thread pool. This name can be chosen freely, for example it can be set to "main pool". If a pool with that name does not exist, it will be automatically created with a pool size of 1. The number of threads can be set by using the :cpp:func:`ln::client::set_max_threads()` method. .. seealso:: * :c:func:`ln_handle_service_group_in_thread_pool()` in the C API .. cpp:function:: ln::client::set_max_threads(std::string pool_name, unsigned int n_threads) Sets the maximum number of threads for a thread pool with the given name. Here, the number ``n_threads`` means: 1. Only one service request can be handled at one time, the requests for the corresponding service groups are handled sequentially. 2. Still, only one service request is handled at the same time, but the setup of the connection is done in an own thread. 3. Up to two service requests can be handled at the same time (and so on). .. warning:: Remember that if different service handlers (or any other parts of the same program) access and modify the same data at the same time, it needs to be protected by :term:`mutexes ` or locks, in order to avoid data corruption. Otherwise, non-deterministic bugs such as :term:`race conditions ` can occur. .. seealso:: * :c:func:`ln_set_max_threads()` in the C API .. cpp:class:: ln::service An object representing a connection to request and handle service calls. Services are accessed by handles. There are two kinds of handles, a service client handle, and a service provider handle, which are created using different functions. Services are functionally similar to ports, in that they describe an open connection, with the difference that they represent a two-way connection which allows to perform remote procedure calls. Class instances can be created by calling :cpp:func:`client::get_service()`, after an LN :cpp:class:`client` instance has been registered. ``service`` instances behave similarly to :class:`port` objects, with the difference that they are designed to be used for a kind of :term:`remote procedure call`, while ports can only be used to write or read messages unidirectionally. .. seealso:: * :c:type:`ln_service` (C API) * :c:type:`ln_service_init` (C API) * :c:type:`ln_service_deinit` (C API) .. cpp:function:: ln::service* ln::client::get_service(std::string service_name,\ std::string message_definition_name, std::string signature) Get a pointer (handle) to a service *client* instance. *service_name* is a string with the name of the service. As with topic names, it can have name space separators in the form of dots ("."). It must not contain slashes (neither within, or at the end). *message_definition_name* (also named service_interface in some headers, but without any different meaning) is a string with the name of the message definition for the service. *signature* is a string which represents the layout of the service message data buffer for a specific service message definition. This signature string is auto-generated by :program:`ln_generate`, which defines a constant in the header :file:`ln_messages.h`, that needs to be included by the C++ program. .. warning:: The resources of the service handle are owned and handled by the client instance. The :term:`life time` of the handle is limited to the life time of the client instance; it cannot be used longer when the client instance get destroyed. .. cpp:function:: ln::service* ln::client::get_service_provider(std::string service_name,\ std::string service_interface, std::string signature) Get a pointer (handle) to a service *provider* instance. .. important:: Note that this handle is *not* usable for a service client! *service_name* is a string with the name of the service. As with topic names, it can have name space separators in the form of dots ("."). It must not contain slashes (neither within, or at the end). *service_interface* is a string with the name of the message definition for the service. *signature* is a string which represents the layout of the service message data buffer for a specific service message definition. This signature string is auto-generated by :program:`ln_generate`, which defines a constant in the header :file:`ln_messages.h`, that needs to be included by the C++ program. .. warning:: The resources of the service handle are owned and handled by the :cpp:class:`ln::client` instance. The :term:`life time` of the handle is limited to the life time of the client instance; it cannot be used longer when the client instance get destroyed. .. seealso:: * :c:func:`ln_service_init()` .. cpp:function:: ln::service* ln::client::release_service(ln::service* cvs) Releases a service handle and the associated resources. This should normally happen only once at program termination. Calling it with an already released service handle leads to a double-free error. *svc* service handle .. seealso:: * :c:func:`ln_service_deinit()` .. _reference/cpp/port_objects: Port Base Class --------------- .. cpp:class:: port_base Is a connection of a subscriber or publisher to send and receive messages of a given type. Ports have two sub-types, one for sending and one for receiving data, .. cpp:member:: unsigned int port_base::message_size Size of the message to be sent or received .. _reference/cpp/outport_objects: Output Ports ------------ .. cpp:class:: outport Handle to connection and buffer for sending messages .. seealso:: * :c:type:`ln_outport` (C API) .. index:: pair: time stamps of logged messages; port::write() pair: synchronization; of messages exchanged by read() and write() .. _reference/cpp/outport/method/write: Output port Methods ^^^^^^^^^^^^^^^^^^^ .. cpp:function:: void ln::outport::write(void * data) .. cpp:function:: void ln::outport::write(void* data, double timestamp) Write and transmit request a packet of message data of length :cpp:member`port_base::message_size`. The data is always transmitted without blocking and completely. Both the connection and the required buffer space are internal parameters of the port instance. *(void*) data* pointer to the start of the data that is being transmitted. The size of the data blob is derived from the message definition that was given at the port's creation. *timestamp*: is a floating-point number which can be used as a time-stamp. The time-stamp can indicate whether data is current, and is also used for rate-limiting, if a subscriber has a rate-limit set. The unit of the timestamp needs to be in seconds. The function can throw an exception if type `exception` in the case of internal errors, which will contain a diagnostic message. TODO: Which exceptions can be thrown, what do they mean, and how are these addressed? .. seealso:: * :c:func:`ln_write` (C API) .. _reference/cpp/inport_objects: Input Ports ----------- .. index:: pair: time stamps of logged messages; port::read() pair: synchronization; of messages exchanged by read() and write() .. cpp:class:: inport An ``inport`` is a connection and buffer space for receiving data via the :cpp:func:`ln::inport::read()` function. .. seealso:: * :c:type:`ln_inport` (C API) .. _reference/cpp/inport/method/read: Input Port Methods ^^^^^^^^^^^^^^^^^^ .. cpp:function:: bool ln::inport::read(void* data, bool blocking=true) .. cpp:function:: bool ln::inport::read(void* data, double timeout) The port ``read()`` method copies an available packet of message data of size :cpp:member`port_base::message_size` after it was been received by the port. Depending on blocking and time-out parameters, it will wait or will not wait when no new data is currently present. *blocking_or_timeout* is a parameter which controls :term:`blocking` and :term:`time-out` behavior: * If it is Boolean ``true`` (which is the default value) and no new data is present, the ``read()`` call will block until new data is available. * If it is a floating point number and no data is available yet, it will wait at most this fractional number of seconds before it returns ``false`` and without transferring data. In this case, the content of the buffer pointed to by ``data`` is not changed. * If it is a number of zero, a negative number, or a Boolean with the value of ``false``, the port will be :term:`non-blocking`: If no new data is present, it will never wait, but immediately return a Boolean ``false``. (For further explanation, see the description :ref:`in the tutorial `.) * in any case, the data is either copied completely or not at all, and if no new data was send, the input buffer will not be changed, keeping its old content. *return value* is a Boolean value of ``true`` if data could be read, and otherwise Boolean ``False``, meaning that either no data was present, or a time-out was set and the time-out expired without receiving data. The function can throw an exception if type `exception` in the case of errors or an unimplemented configuration, which will contain a diagnostic message. For details, please see the C APO reference. .. seealso:: * :c:func:`ln_read()` (C API) * :c:func:`ln_read_timeout()` (C API) * for an overview on how to use publish/subscribe communication with ports and topics, see :ref:`tutorial/cpp/api/summary/publish-subscribe` in the tutorial. .. _reference/cpp/service_class: Service calls (client side) --------------------------- .. cpp:type:: MESSAGE_DEF_NAMESPACE::SVMDEF_NAME_t Message buffer for service data, which has a ``req`` member for request input parameters, and a ``resp`` for the return parameters. .. important:: Both at the client side, and the provider side, the user-accessed buffers need to be allocated by the user program (for example, as an automatic variable on the stack). Apart from the service wrapper class, the LN system does *not* allocate user-accessible memory space for these data. Conseqently, the service request parameters need to be default-initialized by the user, in order to avoid uninitialized memory. Methods ^^^^^^^ .. cpp:function:: ln::service::call(void *data) .. cpp:function:: ln::service::call(MESSAGE_DEF_NAMESPACE::MDEF_NAME_t *request_parameters) Calls an LN service by sending the request parameter struct with the parameters stored in :cpp:member:`MESSAGE_DEF_NAMESPACE::MDEF_NAME_t::req` to the service provider, waiting for a response, and making the result parameters available in the :cpp:member:`MESSAGE_DEF_NAMESPACE::MDEF_NAME_t::resp` data attribute. The user needs to take care that the :cpp:member:`MESSAGE_DEF_NAMESPACE::MDEF_NAME_t::req` is properly initialized for all fields that are not specifically assigned to, for example using the C ``memset()`` function, or an C++ "{}" default initializer. The used data structure with the generated type name MESSAGE_DEF_NAMESPACE::MDEF_NAME_t is not type-checked at compile time. However, it is designed to be a structure definition that is generated by :program:`ln_generate`, which allows to access the data elements safely (see section :ref:`reference/cpp/service_data_buffer`). .. seealso:: * :c:func:`ln_service_call` (C API) * :c:type:`ln_service_handler` (C API) * :c:type:`ln_service_init` (C API) * :c:type:`ln_service_deinit` (C API) * :c:func:`ln_service_provider_set_handler` (C API) * :c:func:`ln_service_provider_register` (C API) * :c:func:`ln_service_request_respond` (C API) .. seealso:: * :c:func:`ln_service_call` (C API) .. cpp:type:: int (*handler_t)(ln::client&, service_request&, void* user_data) User-provided callback function that handles a service request. (In the wrapped API, this function is pre-defined by the wrapper class). .. seealso:: * :c:type:`ln_service_handler` in the C API .. cpp:function:: void ln::service::set_handler(handler_t handler, void* user_data=NULL) Sets a user-provided handler of type :cpp:type:`handler_t` for a service call which needs to have the following signature: .. sourcecode:: c++ int USER_SERVICE_HANDLER(ln::client& clnt, ln::service_request& req, void* user_data) .. seealso:: * :c:func:`ln_service_provider_set_handler()` (C API) .. cpp:function:: int USER_SERVICE_HANDLER(ln::client& clnt, ln::service_request& req, void* user_data) The handler is a function of type :cpp:type:`handler_t` for a user-provided function which accepts a reference to an :cpp:class:`ln::client` instance as a first parameter, a reference to a :cpp:class:`ln::service_request` as the second parameter, and an optional pointer to some user data as third parameter. *user_data* The user data can be some pointer to a class instance or a static variable which provides context to the service call, or it can be used to store state between calls. .. important:: This data pointer is **not** to be confused with message data for a single service request. It is intended to hold memory or a pointer to an object that has the task to respond to these requests, for example a kind of hardware driver or data cache. *req* The req parameter of the handler function prototype is an instance to an :cpp:class:`ln::service_request` object which can retrieve and copy the call parameters using the :cpp:func:`ln::service_request::set_data()` function, and send the response using the :cpp:func:`ln::service_request::respond()` function. *clnt* The :cpp:class:`ln::client` reference is not necessarily used. .. cpp:function:: void ln::service::do_register(const char* group_name=nullptr) Registers a service represented by a service provider handle to be handled in a specific thread group. In difference to :cpp:func:`ln::client::get_service_provider()` and :cpp:func:`ln::service::set_handler()`, this function performs communication with the LN manager. Because network connections are not absolutely reliable, this operation can potentially fail, which will result in an exception. *group_name* The name of the :term:`service group`. If the parameter is ``NULL`` or ``nullptr``, the default service group is used. .. seealso:: * :c:func:`ln_service_provider_register()` (C API) .. cpp:class:: ln::service_request Is a handle to an object which represents a service request, and provides methods to finishing and returning, or aborting the request. Its two primary capabilities are to copy the request data into a user-space buffer (using the :cpp:func:`ln::service_request::set_data()` method), and to return the response data, using the :cpp:func:`ln::service_request::respond()` method. It is also possible to call the service request asynchronously, which is useful for real-time applications in which blocking calls are undesirable. This object does not contain the request and response data — both are accessed via an separate data structure called MESSAGE_DEF_NAMESPACE::MDEF_NAME_t, which is auto-generated by :program:`ln_generate` (see section :ref:`reference/cpp/service_data_buffer`). .. seealso:: * :c:type:`ln_service_request` (C API) .. cpp:function:: int ln::service_request::set_data(MESSAGE_DEF_NAMESPACE::SVMDEF_NAME_t *data, \ char *signature) Copies the transmitted data from the internal LN message buffer for a service message into a user-provided buffer pointed to by data. *data* User-space buffer for the call data. The buffer needs to hold both the request parameters, as well as the response which will be later filled in by the client handler. For the type of this parameter, see section :ref:`reference/cpp/generated-symbols`. *signature* is a string which holds a description of the corresponding message definition, which is auto-generated and has the name MESSAGE_DEF_NAMESPACE::SVMDEF_NAME_signature. This string constant is generated by :program:`ln_generate`. The string has the function to define how much data has to be copied. .. seealso:: * :c:func:`ln_service_request_set_data()` (C API) .. cpp:function:: int ln::service_request::respond() This method needs to be called when a service request has been processed by a service provider process, and the request is returned as successful with the resulting response data and resolved. The result is that the result data in the associated data buffer of type MESSAGE_DEF_NAMESPACE::MDEF_NAME_t is copied back from the user buffer assigned by set-data into the internal LN message buffers, and transmitted to the service client. Any error while transferring the response will raise an exception here. When ``respond()`` returns, the provider can be sure that the response has arrived at the caller, and that both processes have reached the corresponding point of their execution (in other words, the ``respond()`` method provides synchronization between threads and between service clients and the service provider). .. note:: Depending on the used service message definition, the definition can contain variable-length arrays, and in this case, the response can contain pointers to dynamically allocated objects (such as strings) which have a limited :term:`life time`. **In such cases, it is important that ``respond()`` is called before the life time of these objects expires. Otherwise, corrupted data might be returned**. .. seealso:: * :c:func:`ln_service_request_respond()` (C API) .. cpp:function:: bool ln::service_request::is_aborted() Method which allows to check whether a service request was aborted. .. cpp:function:: bool ln::service_request::finished() Method indicating that a service request has been finished. This is used for asynchronous calls. .. cpp:function:: void ln::service_request::abort() Method that aborts a service request. This can be used in asynchronous calls. .. _reference/cpp/generated-symbols: Symbols generated by ln_generate -------------------------------- See the section ":ref:`placeholders used in this description `" above for explanations on the meaning of the placeholders in angle brackets, and how they correspond to the tutorial code examples. Structs generated from Message Definitions (for both topics and services) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. _reference/cpp/service_data_buffer: Service data buffer ^^^^^^^^^^^^^^^^^^^ .. cpp:class:: MESSAGE_DEF_NAMESPACE::MDEF_NAME_t Type with which holds the data for sending the request, and allows to retrieve the result. Is an auto-generated struct type. It contains both the request parameters and the response data for a service call. The service client needs to fill in the request parameter data, before calling the service, and gets the response data in return. Request parameters and response data are defined via two members of of this auto-generated structure type. .. cpp::type:: SERVICE_PREFIX_SERVICE_SUFFIX_MDEF_NAME_request_t Type of a request struct member .. cpp::type:: SERVICE_PREFIX_SERVICE_SUFFIX_MDEF_NAME_response_t Type of a response struct member .. cpp:member:: SERVICE_PREFIX_SERVICE_SUFFIX_MDEF_NAME_request_t MESSAGE_DEF_NAMESPACE::SVMDEF_NAME::req Is a data member object which receives the service request or input parameters from the client. .. seealso:: * :c:type:`ln_service_request` (C API) .. cpp:member:: SERVICE_PREFIX_SERVICE_SUFFIX_MDEF_NAME_response_t MESSAGE_DEF_NAMESPACE::SVMDEF_NAME::resp is a data member which returns the service return parameters to the client. Its content is copied when the :cpp:func:`ln::service_request::respond` function is called. The content of the response buffer needs to be filled in by the called service provider. The data buffer is initialized to zero (using ``memset(void *data, 0, ...)``) before it is handed to the provider function. .. note:: The response object can contain arrays which have a variable number of elements (so-called variable-length arrays). These are represented by pointers to another memory object, typically a dynamically allocated and managed object or buffer space like std::string::c_str(). It is important that the :term:`life time` of these objects is at least as long as to the point where the call to :cpp:func:`ln::service_request::respond` takes place. Classes and Methods auto-generated for service providers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. cpp:class:: MESSAGE_DEF_NAMESPACE::SVMDEF_NAME_base Base class provided by ``ln_generate``, that is used to derive the provider class, which is defined by the developer using LN. .. cpp:function:: MESSAGE_DEF_NAMESPACE::SVMDEF_NAME_base::\ register_SVMDEF_NAME(ln::client, char* service_fullname) Method of the service provide base class which registers the service method, with the name of the service (for example, "elevator.request") as a parameter. .. cpp:function:: PROVIDER_CLASS::on_SVMDEF_NAME \ (ln::service_request& req, \ MESSAGE_DEF_NAMESPACE::MDEF_NAME_t& svc) override Method of the provider class, that is implemented by it, and is run when the service is called, with the service message as a parameter. The method takes the parameter svc, reads the call parameters from ``svc.req``, and when it is ready, it stores the result of the call in ``svc.resp``, and calls ``req.respond()``, which is defined as member function :cpp:func:`ln::service_request::respond()`. .. cpp:function:: PROVIDER_CLASS::run() Method which runs the service provider, and needs to be implemented by the provider class. Symbols generated for service client ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The client class does not need to be derived by a specific base class. It instantiates an object of the type :cpp:class::`ln::service()`, using :cpp:class:`client::get_service()`. .. cpp:function:: CLIENT_CLASS::SVMDEF_NAME() Client function that calls the service, via :cpp:func:`ln::service::call()`. The name of this function is conventional, it is not auto-generated. .. seealso:: For an overview on how to use service calls, the the tutorial section :ref:`tutorial/cpp/api/summary/services` Relevant Source Code Files for further Reference ================================================ C++ API ------- :file:`python/links_and_nodes/libln/include/ln/cppwrapper.h` :file:`python/links_and_nodes/_ln.cpp` C API ----- :file:`python/links_and_nodes/ln_wrappers.py` :file:`libln/include/ln/cpp_wrapper.h` :file:`libln/include/ln/cpp_wrapper_impl.h` :file:`libln/include/ln/ln.h`