7.3.3. Public C API Reference

7.3.3.1. Notes on the C API

This API is mainly used to implement the C++ and the Python API. It is provided here so that you can find, if needed, quite detailed information on its functions. Depending on which programming language you need to use, it might be useful to start to read first with the Python API Reference or the C++ API Reference parts.

7.3.3.2. Thread-Safety

The API functions can be classified into two categories:

  • Functions and constructors which set up connections and configure the client, like the ln_client() constructor, or the ln_subscribe() method.

  • Functions and constructors which perform 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.

7.3.3.3. 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.

7.3.3.4. Memory Management

If functions such as ln_subscribe() return pointers, these are always, unless noted otherwise, non-owning pointers which do not need to be freed by the caller of that function. When they to refer, for example, to ln_client instances, their life time ends when that instance is freed or destroyed, so they cannot be used any more.

7.3.3.5. LN Client

LN client objects are needed for both publish/subscribe communication and for remote procedure calls which are called “services”.

type ln_client

An LN client instance which holds information on the connection. Needs to be initialized using ln_init().

int ln_init(ln_client *clnt, const char *client_name, int argc, char **argv)
Parameters:
  • clnt – is a pointer to an :c:struct:

  • client_name – a default-value to use when there is no LN_PROGRAM_NAME environment variable. The exact behavior is described in Client Name Selection.

  • argc – number of arguments to the program, as supplied to main().

  • argv – pointer to the argument list of the program, as supplied to main().

Return type:

an integer indicating success or failure

connect to ln_manager specified via command line option “–ln-manager HOST:PORT” use LN_MANAGER env-var if there is no such option. will initialize ln_client at address clnt and return 0 on success.

int ln_init_to_manager(ln_client *clnt, const char *client_name, const char *ln_manager)

Connect to specified ln_manager, only use the LN_MANAGER environment variable if ln_manager is empty/NULL. Will initialize ln_client at address clnt and return 0 on success.

char *ln_get_error_message(ln_client clnt_)

To display the dynamically generated error message on this client connection.

The returned char* pointer is owned by the corresponding ln_client object. It must not be freed by user code. It is only valid while that client object still exists, and must not be accessed after the client has been destroyed via ln_deinit().

7.3.3.6. Ports and Topics

Ports link an initialized LN client with a topic and a message definition. For sending data, the topic needs a publisher port, and for receiving data, it needs a subscriber port.

type ln_inport

Input port which results from subscribing to a topic.

type ln_outport

Output port which results from publishing to a topic

int ln_subscribe(ln_client clnt, const char *topic_name, const char *message_definition_name, ln_inport *port, double rate, int reliable_transport)

Subscribe with a message definition to a topic.

The rate is a maximum rate of messages per seconds. If more messages are sent than this rate, they will be discarded.

Error Codes:

NE_CLIENT_NOT_INITIALIZED : the LN client object was not initialized

int ln_subscribe_with_buffers(ln_client clnt, const char *topic_name, const char *message_definition_name, ln_inport *port, double rate, int reliable_transport, unsigned int buffers)
Return type:

ln_outport

Subscribe to a topic, and also specify the number of used buffers

int ln_unsubscribe(ln_inport *port)

Unsubscribe from a topic.

int ln_publish(ln_client clnt, const char *topic_name, const char *message_definition_name, ln_outport *port)

publish to a topic with a given message type

Error Codes:

NE_CLIENT_NOT_INITIALIZED : the LN client object was not initialized

int ln_publish_with_buffers(ln_client clnt, const char *topic_name, const char *message_definition_name, unsigned int buffers, ln_outport *port)

publish to a topic with a given message type, specifying the number of used buffers

int ln_unpublish(ln_outport *port)

7.3.3.7. Sending, Receiving and Handling Message Packets

Packets are pieces of message data that can be sent and received.

7.3.3.7.1. Common Types

typedef void *ln_packet

A pointer to a transmitted data structure whose members can be accessed by name

7.3.3.7.2. Receiving Packets

int ln_read(ln_inport port, void *ln_packet, unsigned int size, double *timestamp, int blocking)

read from the inport and fill the ln_packet with data.

If there is new data, it is copied atomically. Otherwise, the input buffer is not changed.

Parameters:
  • port – the input port

  • ln_packet – the packet data structure that is filled or whose content is transmitted

  • size – the size of the packet

  • timestamp – the timestamp of the package

  • blocking – if true and no data is there, the method waits for new data. If false and no data is there, the method returns immediately without changing the input buffer.

Return type:

Returns 0 if no packet was read, 1 if a packet was read, and a negative value for run-time-errors.

Error return codes (with negative sign):

Return values:
  • 0 – if port does not have yet a publisher

  • LNE_INVALID_PORT_OBJECT – If used without a valid port object

  • LNE_NOT_YET_IMPLEMENTED – parameter combination not yet implemented, e.g. if trying a blocking read with a set request rate

  • LNE_PORT_UNBLOCKED – if port is not blocked (wrong configuration)

  • LNE_SHM_READ_ERROR – read from SHM failed (internal error)

int ln_read_timeout(ln_inport port, void *ln_packet, unsigned int packet_size, double *ts, double timeout)

As for ln_read(), data is either transferred completely, or not at all.

Parameters:
  • port – the input port

  • ln_packet – the packet data structure that is filled or whose content is transmitted

  • size – the size of the packet

  • ts – the timestamp of the package

  • timeout

    an optional time-out with a maximum waiting time in seconds

    timeout parameter: 0 - non-blocking >0 - blocking after <timeout> seconds

Return type:

return value: 0 - the timeout was hit 1 - packet!

7.3.3.7.3. Sending Packets

int ln_write(ln_outport port, void *ln_packet, unsigned int size, double *timestamp)

write a packet to an output port, attaching a time stamp to it (The time stamp is useful to discern otherwise identical packets which arrive in a sequence)

The write is atomically and does not block.

The timestamp is the time in seconds. It is used when rate-limiting messages.

The return code is normally zero and is a negative value for any run-time errors, such as not being able to write to shared memory.

Parameters:
  • port – port handle

  • ln_packet – pointer to packet data

  • size – size of packet

  • timestamp – timestamp of message

Error codes:

Return values:
  • LNE_INVALID_PORT_OBJECT – If used without a valid port object

  • LNE_PACKET_TOO_LARGE – packet was too large for configured message size

7.3.3.8. LN Services

LN services implement a form of remote procedure call. These are split in a service provider and a service client.

7.3.3.8.1. Common Types

type ln_service

An LN service client instance, which can be used by a service client to access functions provided by a service provider

type ln_service_request

7.3.3.8.2. Provider API

The service provider implements the remote call, by registering a handler to a specific service call.

int ln_service_init(ln_client clnt, ln_service *svc, const char *service_name, const char *service_interface, const char *signature)

Initialize a service for a client

Parameters:
  • service_name – The name which identifies the service within the current distributed system.

  • service_interface – The service interface is a string containing the name of the service message definition, which defines both call parameters and return parameters.

  • signature – A string that is auto-generated by ln_generate, that mirrors the data element of a service request and response, and how to copy them.

int ln_service_deinit(ln_service *svc)

Unregister and de-initialize a service, freeing the internal resources associated with it.

typedef int (*ln_service_handler)(ln_client clnt, ln_service_request req, void *user_data)

Type of user-provided handler function to handle service calls. The function will be called with the service request data and with a pointer to arbitrary user data, that can hold server-side state between calls. The user data pointer can be a pointer to a static struct or object instance.

int ln_service_provider_set_handler(ln_service svc, ln_service_handler handler, void *user_data)

Set a handler function to an initialized service. This will cause the handler function to be called if a service request arrives

Parameters:
  • svc – service handle

  • handler – handler function of type ln_service_handler, defined and provided by the user.

int ln_service_provider_register(ln_client clnt, ln_service svc)

Register the service provider setup with the LN manager to provide a service.

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.

Parameters:
  • clnt – LN client

  • svc – service handle

int ln_service_request_respond(ln_service_request req)

Transfers the result of a service call back to the caller.

Any error while transferring the response will cause a non-zero return value. When ln_service_request_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 ln_service_request_respond() method provides synchronization between threads).

Parameters:
  • req – service request handle

int ln_wait_and_handle_service_group_requests(ln_client clnt, const char *group_name, double timeout)

Handle service requests for one service group with the provided client in the current thread, executing requests of one service group serially in the current thread. If the data accessed by the request handlers is not modified concurrently by additional threads, no thread synchronization is necessary.

Note

Concurrent calls of ln_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 ln_handle_service_group_in_thread_pool() when service handlers should run concurrently.

Parameters:
  • clnt – LN client

  • group_name – name of the service group for which requests are handled. The parameter NULL/nullptr refers to the default group.

  • 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.

int ln_handle_service_group_in_thread_pool(ln_client clnt, const char *group_name, const char *pool_name)

Handle service requests for one service group in a thread pool, potentially executing them in parallel. Write access to common resources needs to be secured by locks/mutexes in the handler implementation.

Important

This function is mutually exclusive with ln_wait_and_handle_service_group_requests(), only one of both functions must be called.

Parameters:
  • clnt – LN client

  • group_name – name of the service group. The parameter NULL refers to the default group.

  • pool_name – name of the thread pool. If a pool with that name does not exist, it will be automatically created with a pool size of 1.

int ln_set_max_threads(ln_client clnt, const char *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).

int ln_service_request_set_data(ln_service_request req, void *data, const char *signature)

This function does two things:

  1. It registers a pointer to a data buffer, which is used in the operation of the respond() function to retrieve the response data for a service call.

  2. It copies the request paremeter data from the LN internal buffer to that data buffer.

The buffer pointed to by data has to be managed by the user - it is neither automatically allocated, nor freed by LN.

Parameters:
  • req – service request handle

  • data – pointer to data buffer which serves to receive request data, and will provide reponse data when the call is responded to with respond().

7.3.3.8.3. Client API

The client can call the service function, which can be executed on another node. This service call is completely network-transparent.

int ln_service_call(ln_service svc, void *data)

Call the service from the client

7.3.3.9. message definitions

The client can query information about message definitions known to the LNM. it can also register new message definitions at runtime (useful when md is generated dynamically).

int ln_get_message_definition_v21(ln_client clnt, const char *message_definition_name, char **message_definition, unsigned int *message_size, char **hash, char **flat_message_definition)

get information about a named message definition.

Parameters:
  • clnt – LN client

  • message_definition_name – the name of the used message definition to get information for.

  • message_definition – output-parameter, might be NULL. needs to be freed by caller. will point to a python-text-representation of the message structure.

  • message_size – output-parameter, might be NULL. size in bytes of a packet according to this message definition.

  • hash – output-parameter, might be NULL. needs to be freed by caller. will point to a hex-string-representation of a hash which is computed for this message structure.

  • flat_message_definition – output-parameter, might be NULL. needs to be freed by caller. will point to an internal text-representation of the message structure.

example for md uint32_t from tests/local_publish_subscribe:

  • message_definition:

    {'defines': {'st': [['uint32_t', 'data', 1],
                        ['float', 'f1', 1],
                        ['char', 'f1_text', 8],
                        ['float', 'f8', 8]]},
                 'fields': [['uint32_t', 'data', 1],
                            ['uint64_t', 'bigdata', 1],
                            ['float', 'f1', 1],
                            ['char', 'f1_text', 8],
                            ['float', 'f8', 8],
                            ['double', 'd1', 1],
                            ['double', 'd8', 8],
                            ['char', 'long_text', 1024],
                            ['double', 'd80', 80],
                            ['st', 'st1', 1],
                            ['st', 'st3', 3]],
                 'resp_fields': []}
    
  • message_size:

    1984
    
  • hash:

    275d98fd43f228c6e8447070d1271675306eab30e16bd6e21f5c936e7b303b73
    
  • flat_message_definition:

    7 4 1 data|-2 8 1 bigdata|1 4 1 f1|2 1 8 f1_text|1 4 8 f8|0 8 1 d1|0 8 8 d8|2 1 1024 long_text|0 8 80 d80|7 4 1 st1_data|1 4 1 st1_f1|2 1 8 st1_f1_text|1 4 8 st1_f8|7 4 1 st3_data[0]|1 4 1 st3_f1[0]|2 1 8 st3_f1_text[0]|1 4 8 st3_f8[0]|7 4 1 st3_data[1]|1 4 1 st3_f1[1]|2 1 8 st3_f1_text[1]|1 4 8 st3_f8[1]|7 4 1 st3_data[2]|1 4 1 st3_f1[2]|2 1 8 st3_f1_text[2]|1 4 8 st3_f8[2]|
    
int ln_get_message_definition_for_topic_v17(ln_client clnt, const char *topic_name, char **message_definition_name, char **message_definition, unsigned int *message_size, char **hash)

get message definition that is used by named topic.

Parameters:
  • clnt – LN client

  • topic_name – name of the topic. The topic-name must be in use by some other LN-Client (subscriber or publisher).

  • message_definition_name – output-parameter. needs to be freed by caller. will point to the name of the used message definition.

  • message_definition – output-parameter. needs to be freed by caller. will point to a python-text-representation of the message structure.

  • message_size – output-parameter. size in bytes of a packet according to this message definition.

  • hash – output-parameter, might be NULL. needs to be freed by caller. will point to a hex-string-representation of a hash which is computed for this message structure.

int ln_describe_message_definition(ln_client clnt, const char *message_definition_name, char **message_definition)

get a human readable description for a named message definition.

Parameters:
  • clnt – LN client

  • message_definition_name – the name of the used message definition to get information for.

  • message_definition – output-parameter. needs to be freed by caller. will point to a human-readable text-representation of the message structure including any used non-primitives/subtypes.

example for md uint32_t from tests/local_publish_subscribe:

name: uint32_t
file: /home/schm_fl/.../tests/local_publish_subscribe/mds/uint32_t
type: packet
fields:
  uint32_t data
  uint64_t bigdata
  float f1
  char f1_text[8]
  float f8[8]
  double d1
  double d8[8]
  char long_text[1024]
  double d80[80]
  st st1
  st st3[3]
non primitives:
  st: subtype
---
name: subtype
file: /home/schm_fl/.../tests/local_publish_subscribe/mds/subtype
type: packet
fields:
  uint32_t data
  float f1
  char f1_text[8]
  float f8[8]
int ln_put_message_definition(ln_client clnt, const char *message_definition_name, const char *message_definition, char **real_message_definition_name)

register a new message definition with LNM. dynamically generated message definitions will always have a name-prefix of gen/ to clearly distinguish them from well-known/published message definitions.

Parameters:
  • clnt – LN client

  • message_definition_name – requested name of the new message definition.

  • message_definition – source of to be created message definition. this is the same what you would write into a md-file. (do not put the gen/ prefix here)

  • real_message_definition – output-parameter. needs to be freed by caller. will point to the name of the new message-definition with the LNM-decided gen/-prefix.

7.3.3.10. C API Error Codes and their Meaning

Error Code

Meaning

LNE_CHECK_ERRNO

check errno for error description

LNE_NO_MEM

out of memory

LNE_NO_MANAGER_ADDRESS

no –ln-manager HOST:PORT command line argument and no LN_MANAGER environment var

LNE_INVALID_MANAGER_ADDRESS

specified ln_manager address is not in format HOST_OR_IP:PORT_NUMBER

LNE_INVALID_HOSTNAME

invalid hostname specified - has to be a hostname or an ip

LNE_UNKNOWN_HOSTNAME

could not resolve hostname

LNE_HOST_WRONG_NET

host resolved to wrong network family - should be IPv4 - AF_INET

LNE_GOT_INVALID_RESPONSE

client library received an invalid formatted response from ln_manager

LNE_REGISTER_DENIED

ln_manager denied register-request

LNE_CLIENT_NOT_INITIALIZED

provided client instance is not initalized!

LNE_REQUEST_FAILED

the request to ln_manager failed / was not successfull - see ln_get_error_message()

LNE_FIELD_NOT_IN_HEADER

the requested field name was not found in this request object

LNE_STRING_LENGTH_SPEC_MISSING

string length specification is missing in string format!

LNE_PORT_NOT_FOUND

the specified port was not found!

LNE_INVALID_PORT_OBJECT

the specified object is not or a wrong port object!

LNE_SHM_IS_TOO_SMALL

the requested shared memory region is too small!

LNE_SHM_IS_TOO_BIG

the requested shared memory region is too big!

LNE_SHM_DOES_NOT_EXIT

the requested shared memory region does not exist!

LNE_PACKET_TOO_LARGE

the provided packet is too large to write to this port!

LNE_SHM_READ_ERROR

error reading from shared memory source!

LNE_LOST_CONNECTION

lost connection to ln_manager

LNE_REGISTER_FAILED

could not register client to manager! is a ln_daemon running on this host?

LNE_SVC_IS_PROVIDER

this is a service provider not a service client!

LNE_SVC_IS_CLIENT

this is a service client not a service provider!

LNE_SVC_RECV_RESP

error receiving service response

LNE_SVC_RECV_RESP_MEM

error receiving service response: can not allocate sufficiently sized buffer

LNE_SVC_ALREADY_REGISTERED

this service already has an opened socket - is it already registered

LNE_SVC_NOT_REGISTERED

this service is not yet registered - it has no opened socket!

LNE_SVC_RECV_REQ

error receiving service request

LNE_SVC_RECV_REQ_MEM

error receiving service request: can not allocate sufficiently sized buffer

LNE_SVC_REQ_SET_DATA_WRONG

wrong signature passed to ln_service_request_set_data() for this service!

LNE_SVC_HANDLER_NO_RESP

programming error in service provider handler: handler returned success(==0) but did not call ln_service_request_respond()!

LNE_INVALID_REQ_FIELD_FORMAT

init_request failed because of an invalid format character! use one of r O,d,f!

LNE_USER_DEFINED_ERROR

user-defined error number

LNE_SVC_NO_HANDLER

can’t register service without service-handler! use ln_service_provider_set_handler()!

LNE_SVC_HANDLER_EXC

exception was thrown in service provider handler!

LNE_SVC_REQ_RUNNING

there is already a service request/call running for this service!

LNE_SVC_REQ_NOT_RUNNING

there is not async service request running!

LNE_SVC_REQ_ABORTED

this async service request was aborted!

LNE_NO_PROVIDER_FOUND

there is no known provider for this service/topic!

LNE_START_PROVIDER_FAILED

there was an error starting a provider for this service/topic!

LNE_ERROR_GETTING_SHM_FD

there was an error trying to get a fd for this shm name

LNE_SHM_NAME_TOO_LONG

the shared memory name is too long

LNE_NOT_YET_IMPLEMENTED

the requested feature is not yet implemented

LNE_NO_LOGGER_TOPICS

there are no topics defined for this logger

LNE_INTERNAL_ERROR

internal error, should not happen!

LNE_TOPIC_ID_OUT_OF_RANGE

supplied logging_data topic_id is out of range!

LNE_LOG_FILE_TOO_NEW

this logfile uses an unknown/too new fileformat!

LNE_WRONG_BYTE_ORDER

data has wrong byte order. usually this means its different than the host-byte-order

LNE_INVALID_SHM_MAGIC

invalid shm magic - recompile creator of this shm!

LNE_SHM_VERSION_TOO_NEW

shm version too new! recompile this client!

LNE_WRONG_SHM_SIZE

shm reports too small / invalid segment size!

LNE_INVALID_SIGNATURE

passed signature is not a valid event signature!

LNE_INVALID_PARAMETER

user-provided parameter is invalid!

LNE_SVC_RESP_LATER

this service request will be answered later…

LNE_SVC_GRP_UNKNOWN

this service group name is not known!

LNE_THREADP_INIT

could not get thread pool!

LNE_NOT_ON_THIS_OS

feature not avaliable on this os!

LNE_PORT_UNBLOCKED

another thread unblocked this blocking read

LNE_UNKNOWN_PARAMETER

unknown parameter specified

LNE_SVC_HANDLER_MULTI_RESP

programming error in service provider handler: handler tried to call ln_service_request_respond() more than once!!

LNE_MANAGER_TOO_OLD

the connected ln_manager is too old

LNE_INVALID_DSA_SIGNATURE

the dss1-dsa signature is not valid for this message & public