libevopen62541

Integrating open62541 into an existing libev event loop


I have an existing application that makes extensive use of libev for its event loop. I would now like to add OPC UA server functionality, but am unsure how best to integrate the open62541 event loop into libev.

The following possibilities come to mind:

  1. Call UA_Server_run_iterate from within the libev event loop with a waitInternal time of 0. This would either mean that the server could never sleep (polling open62541 in an ev_idle), or that requests from an OPC UA client would experience an additional latency of up to 50ms (the default max wait time of open62541).
  2. Patch open62541 to allow retrieval of the file descriptors currently in use (serverSockets and connections) by the server network layer. This would allow adding libev events for those file descriptors, which could in turn poll UA_Server_run_iterate only when necessary.
  3. Implement a custom server network layer that makes use of libev. This seems to imply quite a bit of code duplication... Are there any examples/tutorials for implementing a custom network layer?
  4. Run the open62541 event loop in a separate thread. I really really really want to avoid this, since the whole purpose of an event system such as libev is to avoid issues associated with asynchronous operation. For example, all callbacks from open62541 would have to synchronize with the the main libev thread.

Which of the above options would you consider "best" in terms of complexity and performance?

Can you think of any other options not listed above?


Also posted on open62541 mailing list.


Solution

  • I'd recommend either option 1 or option 2. (Disclaimer: I'm one of the core devs of open62541)

    1. Call UA_Server_run_iterate from within the libev event loop with a waitInternal time of 0. This would either mean that the server could never sleep (polling open62541 in an ev_idle), or that requests from an OPC UA client would experience an additional latency of up to 50ms (the default max wait time of open62541).

    For now this is probably the best option you could go. You can call UA_Server_run_iterate in a fixed interval, e.g., every 10ms, depending on the requirements of the application. All the other options require patching of open62541 and currently there's a lot going on in the internal API since many features are being added currently. Also have a look at my note at the end!

    1. Patch open62541 to allow retrieval of the file descriptors currently in use (serverSockets and connections) by the server network layer. This would allow adding libev events for those file descriptors, which could in turn poll UA_Server_run_iterate only when necessary.

    You probably do not need to patch open62541 since you can get the file descriptor of the socket through the network layer of the server config if the network layer is a TCP layer: server->config.networkLayers[i].serverSockets[j]. This may also introduce a lot of maintenance work since there can be different kinds of network layers. E.g. pubsub is using UDP where the sockets are stored inside of config->pubsubTransportLayers

    1. Implement a custom server network layer that makes use of libev. This seems to imply quite a bit of code duplication... Are there any examples/tutorials for implementing a custom network layer?

    You could implement your own network layer using the plugin interface, i.e., write your own (https://github.com/open62541/open62541/blob/master/arch/ua_network_tcp.c). Since this is using an internal API, you can expect a lot of maintenance work and patch-fixing. -> Too much work

    1. Run the open62541 event loop in a separate thread. I really really really want to avoid this, since the whole purpose of an event system such as libev is to avoid issues associated with asynchronous operation. For example, all callbacks from open62541 would have to synchronize with the the main libev thread.

    I'd say this is not a good option since you introduce async callbacks.


    General note:

    We currently have an internal draft and sketch to rework the network interface, especially having one select for all the socket FDs. Currently we have multiple selects for multiple FDs.

    Also have a look at the following PR where we already started with the rework: https://github.com/open62541/open62541/pull/2271