in reply to Systemd socket activated service in perl

Thanks to everyone for the help here, especially tybalt89.

Bringing it all together and testing it on an Ubuntu 22.04 VM, I have this simplified perl script:

#!/usr/bin/perl # Minimal systemd socket activated service # Put together based on responses from: https://www.perlmonks.org/?nod +e_id=11157093 use strict; use warnings; use English; $OUTPUT_AUTOFLUSH = 1; # AKA $| # Important. We need to know the remote IP address. my $remote_addr = $ENV{REMOTE_ADDR}; printf "Greetings %s what is your command?\n", $remote_addr; # printf "%s = %s\n", $_, $ENV{$_} foreach sort keys %ENV; # Us +ed to get the rest of the environment. # Code here to check that $remote_addr is authorised to connect, and w +hich remote commands it may call. # Need to close the socket & refuse futher commands $remote_addr is no +t authorised. while( my $cmd = <> ) { if( $cmd =~ m/^sleep (\d+)/ ) { my $snooze_time = $1; printf "Will sleep for $snooze_time seconds\n"; sleep $snooze_time; print "... ZZZ ... Yawn ... What next oh master?\n"; } # NB: In real life there are lots of other commands and many take +some time to process. else { print "I did not understand that. What next oh master?\n"; } }

With two systemd unit files:

The socket:

/etc/systemd/system/pfs.socket

[Unit] Description=perl forking socket PartOf=pfs.service [Socket] ListenStream=2345 BindIPv6Only=both Accept=yes MaxConnections=12 [Install] WantedBy=sockets.target

And the service:

/etc/systemd/system/pfs@.service

[Unit] Description=perl forking server After=network.target nss-user-lookup.target Requires=pfs.socket [Service] ExecStart=/root/path/to/minimal_systemd_socket_activated_service.pl StandardInput=socket [Install] Also=pfs.socket WantedBy=multi-user.target

Once all three files are installed on the sever:

It should then be possible to test the service:

echo "sleep 30" | nc localhost 2345 -NC

Notes and observations:

Like a CGI script, when the socket activated service is running, STDIN and STDOUT are the socket to the remote client, so printf debugging and logging does not work as expected.

Similar to a cron job, the socket activated service gets very few environment variables set. It is possible to add Environment="variable=value" entries into the Service stanza of the pfs@.service file.

The service file should have an @ symbol in the name. It is not a mistake. In other types of systemd units, the @ symbol means that the service is parameterised, and we should expect to see a %i placeholder in the service unit file. For the socket activated service, the socket sets up the parameters when it invokes the service.

I connected to the service to start a lengthy sleep, then ran systemctl status pfs.socket

This gave an extra Triggers entry that is not show when the socket is idle.

root@Ubuntu:~# systemctl status pfs.socket
● pfs.socket - perl forking socket
     Loaded: loaded (/etc/systemd/system/pfs.socket; enabled; vendor preset: enabled)
     Active: active (listening) since Sun 2024-01-21 10:18:43 GMT; 9min ago
   Triggers: ● pfs@5-127.0.0.1:2345-127.0.0.1:39394.service
     Listen: :::2345 (Stream)
   Accepted: 6; Connected: 1;
      Tasks: 0 (limit: 9361)
     Memory: 8.0K
        CPU: 1ms
     CGroup: /system.slice/pfs.socket

I was then able to get the status of the temporary service:

root@Ubuntu:~# systemctl status pfs@5-127.0.0.1:2345-127.0.0.1:39394.service
● pfs@5-127.0.0.1:2345-127.0.0.1:39394.service - perl forking server (127.0.0.1:39394)
     Loaded: loaded (/etc/systemd/system/pfs@.service; disabled; vendor preset: enabled)
     Active: active (running) since Sun 2024-01-21 10:27:42 GMT; 11s ago
TriggeredBy: ● pfs.socket
   Main PID: 3225 (minimal_systemd)
      Tasks: 1 (limit: 9361)
     Memory: 1.2M
        CPU: 5ms
     CGroup: /system.slice/system-pfs.slice/pfs@5-127.0.0.1:2345-127.0.0.1:39394.service
             └─3225 /usr/bin/perl /root/path/to/minimal_systemd_socket_activated_service.pl

And investigate the environment variables of that service

root@Ubuntu:~# cat /proc/3225/environ | xargs -0 -n1
LANG=en_GB.UTF-8
LANGUAGE=en_GB:en
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
REMOTE_ADDR=127.0.0.1
REMOTE_PORT=39394
INVOCATION_ID=73c1fa9b1e8b45c0a557538dce370fd6
SYSTEMD_EXEC_PID=3225