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 theln_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_NAMEenvironment 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_MANAGERenv-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_MANAGERenvironment 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 correspondingln_clientobject. 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 vialn_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_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, theln_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 useln_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_threadsmeans:Only one service request can be handled at one time, the requests for the corresponding service groups are handled sequentially.
Still, only one service request is handled at the same time, but the setup of the connection is done in an own thread.
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:
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.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_tfromtests/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:1984hash: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_tfromtests/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 |
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 |