Systemd socket based activation

In the previous post we have seen how to start a simple deamon with systemd. Now we will use the socket based activation of this init system to make our daemon start when it is needed.

Let’s start with a basic server which only prints a message.

#include <stdio.h>
#include <stdlib.h>
#include "CommonLib/net_socket.h"

void panic(lerror *error) {
	lstring *buf = NULL;
	
	l_assert(error!=NULL);
	buf = lstring_new();
	buf = lerror_fill_f(error, buf);
	fprintf(stderr, "%s", buf);
	lstring_delete(buf);

	abort();
}

int main() {
	lerror *myError = NULL;
	TCPListenSocket *listeningSocket = NULL;
	TCPSocket *socket = NULL;

	listeningSocket = TCPListenSocket_new("0.0.0.0", 
		"3233", &myError);	
	if (myError!=NULL) panic(myError);

	puts("Hello server is accepting connections"); 
	fflush(stdout);
	
	while(1) {
		socket = TCPListenSocket_accept(listeningSocket, 
			&myError);
		if (myError!=NULL) panic(myError);

		TCPSocket_send_string(socket, 
			"Hello from the server!", &myError);
		if (myError!=NULL) panic(myError);

		TCPSocket_destroy(socket);
		socket = NULL;
	}

	TCPListenSocket_destroy(listeningSocket);
	return 0;
}

This code is based on the CommonLib library.
Now, if systemd started us, we need to get the listening file descriptor and to do so with must include the systemd header file:

#include <systemd/sd-daemon.h>

and to replace:

	listeningSocket = TCPListenSocket_new("0.0.0.0", 
		"3233", &myError);	
	if (myError!=NULL) panic(myError);

with:

	if (sd_listen_fds(0)==0) {
		listeningSocket = TCPListenSocket_new("0.0.0.0", 
			"3233", &myError);
		if (myError!=NULL) panic(myError);
	} else {
		listeningSocket = TCPListenSocket_new_from_fd(
			SD_LISTEN_FDS_START + 0, 
			"localhost:3233");
		puts("Hello server received socket from SystemD"); 
		fflush(stdout);
	}

The sd_listen_fds function will count the sockets passed by systemd and, if systemd started us, the file descriptor SD_LISTEN_FDS_START + 0, the first, is encapsulated in a TCPListenSocket object. The server then follows in the same way. Simple, isn’t?

Now our server is socket activatable. We must tell it to systemd writing a my_server.socket like this:

[Socket]
ListenStream=3233

[Install]
WantedBy=sockets.target

We must also write a my_server.service file like this:

[Unit]
Description=<description here>
After=network.target

[Service]
User=<user name here>
ExecStart=<executable file name here>

Note that this service file has not the install section.

These files must be placed in our /usr/lib/systemd/system directory.
We can make systemd preallocate the socket for us with:

# systemctl start my_server.socket

If you ask your system for the running processes you will not see the daemon process.
When you will make the first connection systemd will start it.

Advertisements
Systemd socket based activation

4 thoughts on “Systemd socket based activation

  1. magnificent post, quite informative. I wonder why the other specialists of this sector do not notice this. You need to continue your writing. I’m sure, you’ve an excellent readers’ base already!

  2. Robert M. Koretsky says:

    CommonLib references and calls unfortunately make this unusable for me, if you were to present this example without that, it would be much more understandable for an ordinary systemd programmer.

    1. Hi Robert.

      I used CommonLib to make the code more understandable. Without CommonLib socket calls would be mixed with socket preallocation ones.

      I think it would be easy to implement another example that doesn’t use CommonLib calls.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s