6.2. Components and their Usage

6.2.1. LN Manager

6.2.1.1. The LN Manager GUI

6.2.1.1.1. Inspecting topics

6.2.1.1.2. Inspecting services

6.2.1.1.3. Re-Connecting to running Processes

6.2.1.2. The LN Manager CLI Interface

6.2.1.3. The LN Manager Configuration File

6.2.1.3.1. Configuring Processes

6.2.1.3.1.1. Accessing the X Server from a client

See X11 Connections and Authentication for a dedicated explanation of X11 display selection, authentication cookies, xauth, xhost, and how ln_manager’s forward_x11 support relates to that.

6.2.1.3.1.2. Setting the default output encoding for Python

TODO: explain why and when setting the output encoding is necessary

add environment: LANG=en_US.UTF-8
add environment: PYTHONIOENCODING=utf-8
output_encoding: utf-8
  • user authentication

  • passing X11 connections

  • debugging and warnings

  • networking configuration & options

6.2.1.3.2. Setting resource limits

6.2.1.3.3. starting processes on remote hosts

Processes both on remote hosts and on the host which the ln manager is running on (the “localhost”) are started using the ln_daemon. Most of the LN daemon operation happens transparently and automatically, so very little configuration is needed. For more details, see section The LN Daemon.

See also

For more information on how to configure processes, you can look at the process section section of the configuration reference.

Also, starting process on remote computers uses a special program, called the LN daemon. Normally, it starts automatically, but if you have any difficulty, please refer to section The LN Daemon in the user guide part.

6.2.1.3.4. controlling the LN manager via the command line interface

6.2.1.3.5. defining LN state objects and what they are good for

6.2.1.3.6. inspecting services interactively

6.2.1.3.7. Defining, setting and using Parameters

6.2.1.3.8. Network Configuration

6.2.1.3.9. Message communication

6.2.1.3.10. Message Definitions

6.2.1.3.10.1. Some hints on how to use topics and messages
  • Message definitions are part of the interface of a software module. They should not be changed after their release - use versioned names, like counter2, if you should need to change them.

  • It is a good idea to standardize and document message definitions and re-use them if this makes sense.

  • Do not forget to document and explain what information topics in your system transport. This is very helpful to understand information exchange and the architecture of a system.

6.2.1.3.10.2. Nested Message definitions

6.2.1.3.11. The ln-generate Tool: creating interfaces for the C++ API

ln_generate reads LN message definition files and generates a C/C++ header, usually named ln_messages.h. C++ clients include that header to get the generated structs, message definition names, message definition hashes, and wrapped service base classes used by the C++ API.

For CMake projects that consume LN through Conan, use the generate_ln_message_headers() helper exported by the liblinks_and_nodes package instead of writing a custom add_custom_command for ln_generate manually. The helper finds ln_generate, forwards the message-definition search path, tracks the message-definition files as build dependencies, and adds an interface target that contributes the generated include directory.

The minimal CMake example is in documentation/examples/guide/cmake_consume_libln/. Its CMakeLists.txt is:

 1cmake_minimum_required(VERSION 3.16)
 2project(cmake_consume_libln CXX)
 3
 4find_package(liblinks_and_nodes REQUIRED CONFIG)
 5
 6generate_ln_message_headers(ln_messages
 7  OUTPUT generated/ln_messages.h
 8  MESSAGES
 9    ln2/pyobject
10    ln2/pyservice
11    ln/log_service
12    tests/time_service
13)
14
15add_executable(cmake_consume_libln main.cpp)
16target_link_libraries(cmake_consume_libln
17  PRIVATE
18    liblinks_and_nodes::liblinks_and_nodes
19    ln_messages_lib
20)
21
22install(TARGETS cmake_consume_libln DESTINATION bin)

The example Conan recipe declares the LN library and message-definition packages as normal requirements, and declares links_and_nodes_base_python as a tool requirement because that package provides ln_generate:

 1from conan import ConanFile
 2from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
 3
 4
 5class CMakeConsumeLiblnConan(ConanFile):
 6    name = "cmake_consume_libln"
 7    version = "test"
 8    package_type = "application"
 9    settings = "os", "compiler", "build_type", "arch"
10    exports_sources = "CMakeLists.txt", "main.cpp"
11    generators = "VirtualBuildEnv", "VirtualRunEnv"
12
13    def requirements(self):
14        self.requires("liblinks_and_nodes/[~2]@common/stable")
15        self.requires("links_and_nodes_ln_msgdef/[~2]@common/stable")
16
17    def build_requirements(self):
18        self.tool_requires("links_and_nodes_base_python/[~2]@common/stable")
19
20    def layout(self):
21        cmake_layout(self)
22
23    def generate(self):
24        toolchain = CMakeToolchain(self)
25        toolchain.generate()
26
27    def build(self):
28        cmake = CMake(self)
29        cmake.configure()
30        cmake.build()
31
32    def package(self):
33        cmake = CMake(self)
34        cmake.install()

For Makefile-based projects or command-line debugging, ln_generate can still be called directly. Pass -o for the output header and one or more message-definition names. Use --md-dir for local message-definition directories that are not already provided through LN_MESSAGE_DEFINITION_DIRS.

6.2.2. The LN Daemon

The LN daemon is a program component which is used by the LN manager. It has two main functions:

  1. to start, stop and control required processes on remote hosts

  2. to relay messages for topics and services over a network

It is designed to mostly work transparently and without user intervention (and therefore, very little information is needed to cover it).

6.2.2.1. Starting LN daemons

There are three ways which an LN daemon can be started:

  1. Automatically at system boot-up. For this, it needs to be configured as a system service which is started by systemd (or similar).

  2. Automatically by the LN manager via a remote SSH connection. For this to work, for a remote machine, the SSH configuration needs to allow for a password-less remote login. In normal cases, this will use the “authorized_keys” feature and the “ssh-agent” program, which allows to unlock a local key, and starts programs such as the LN manager which use it.

    Note that starting a daemon in this way does not require any root access to a computer - this is intended to make it easy to move between networked computers for program development, and embedded computers which might have looser restrictions, in order to allow for hardware access.

  3. If the LN manager cannot start a daemon, one also can start an instance manually, using the ln_daemon command.

Note

Configuring ssh clients and the sshd daemon is outside of the scope of this manual. If you need more information on how to configure an ssh connection, please consult the system man page on ssh_config, ssh-keygen, ssh-agent, and ssh-add. The detail setup may vary depending on your local administration policy.

6.2.2.2. Daemon instances

LN daemons start with an initial process, which is also called the arbiter, and fork from that into child processes which perform communication and management of LN processes on a specific host. Each child process or daemon instance is owned by exactly one user. After a user has connected to it, it will only carry out commands for that user, and reject commands from other users.

When the user stops all processes on a specific node via the LN manager, his daemon instance will also be ended. The arbiter instance will not be stopped.

6.2.2.3. Daemon Authentication

Normally, daemons run as user processes, which means their privileges are restricted to that of the corresponding user. Because daemons can start arbitrary commands and processes, there are two potential issues related to security and safety:

  1. The daemon instance can read any data from the user that it belongs to (both local data and data that might, for example, be accessible via NFS), which can affect security-relevant data such as for example mail passwords, or github keys. This means that exposing confidential data from that user to other users must be prevented.

  2. Because the daemon forwards any messages from that user to LN clients, it can also send unrestricted commands to robots which are controlled by that user. However, robotic systems are normally designed in a way that important control components, such as goal-planning modules or GUI displays, mirror the state of controlled low-level components, such as motors, using a local copy of that state. As a consequence, simultaneous sending of commands from other users, which might be physically unsafe or even hazardous, must be prevented.

To secure the daemon connection, daemons require some basic authentication: any daemon which starts to accept commands from one user therefore becomes locked to this user, meaning that it will not accept connections from any different user.

This is achieved in the following way: First, the daemon gets passed a so-called public key. This can be carried out by starting the daemon with the path to a key file, from which the daemon will read this key.

If a daemon is not locked at start-up, and is first contacted, the LN manager will send it a key. The daemon will then register this key. The alternative is sometimes more practical, but in general it is less preferable than locking the daemon at start-up.

Note

If no key is already available, the LN manager will generate and store a pair of keys, which by default will have the names $HOME/.ssh/id_dsa_ln_daemons.pub for the public key, and $HOME/.ssh/id_dsa_ln_daemons for the corresponding private key [1].

Second, whenever an LN manager creates a new connection to an already running LN daemon, the daemon will request the LN manager to authenticate itself. This is done by so-called public-key cryptography. Basically, the LN daemon sends to the LN manager a random message, and the LN manager signs that massage by using the private key corresponding to the daemons public key. This key is owned by the user, and which nobody else knows. Then, it sends the message back to the LN daemon. The daemon can now use the public key mentioned before to check that it matches the private key, and, if succeeding, will grant the LN manager access.

In specific situations where the LN daemon can neither access private data from the user, nor trigger any potentially unsafe robotic actions, the authentication can be switched off.

Warning

Do not switch off authentication without a good grasp of the security implications!

Note

The authentication described here does not encrypt communication between LN manager and LN clients, because that would be very costly in terms of CPU time, but also, complexity. In certain circumstances, this could be exploited. For example, if the LN manager updates device firmware by sending a firmware image and a password which is needed for flashing the firmware, the password would be visible to any attacker who manages to sniff the network traffic. In this case, the password would need to be protected by other means.

The normal way of authentication, which is by using a file with the public key which is passed at start-up of the daemon, requires that this file is present and visible at the host where the daemon runs, and at the time when it starts.

If it is a robotic system which e.g. has no NFS access, the public key file consequently needs to be copied manually from $HOME/.ssh/id_dsa_ln_daemons.pub to the user home of that file system. It can simply be copied to that computer by whatever tool is available, for example using the scp command (which is always available if ssh access is configured).

6.2.2.3.1. Common Problems and Failure Modes

The authentication has the effect that the communication is much safer, and many errors caused by misunderstandings will be avoided. For example, if two users try to run the same robot from several LN instances, this will not work: The second LN manager instance which is started will report that it cannot connect to the host that controls the hardware.

On the other hand, there are a few failure modes which users should check for when things do not work as expected:

  1. If an LN daemon or a node does not respond to LN commands, it should be checked that the LN daemon belongs to the user which wants to run the command.

  2. If several users share the same user identity on a mobile robot, this can easily cause problems, which can only be avoided by planning for exclusive access at the same time to the robot or system.

    Generally, users (that means, people) should not share identities (multi-user systems, version control software like git, and also systems such as Conan are simply not designed for it).

  3. If a user changes or resets his/her public key, it must stop and re-start any LN daemon which uses the old key. As long as the LN manager which started a daemon is running, this can be done by stopping all processes. Otherwise, it is necessary to stop the daemon manually, by logging in into the remote computer, and using the Unix kill or pkill command, and then start it again.

  4. If a user works on a robot system and wants to stop so that another user can continue to work on it, he or she has to stop all processes, so that there is not daemon left around which will be still locked to him.

6.2.2.4. LN Daemon configuration

  • The ln_daemon program can be configured to receive its public key from a specific file file. This is explained in sections daemon_private_key_file and daemon_private_key_file of the “hosts” section of the configuration reference.

  • Also, the path of the ssh binary can be configured via the option ssh_binary.

  • Finally, the user that the LN daemon expects to connect to can be configured, see expected_user for more details.

Otherwise, the LN daemon has very little configuration options, because it was designed with the goal to work transparently (i.e., in an “invisible” manner), and require as little configuration as possible.

Footnotes