You are not logged in.

#1 2016-01-20 18:48:25

gv
Member
Registered: 2016-01-20
Posts: 3

Systemd socket files stdin redirection

I'm trying to run a normal program as a service, and redirect its stdin/out to a systemd socket. I can get the service to start, but the program doesn't seem to be reading anything from stdin.
Just for testing, I wrote a simple php program that just echoes back any input, but even this doesn't work (it does work if started from the shell though.)
So there must be something wrong in my service or socket files.. (Or do I have the wrong expectations from systemd sockets?)

/etc/systemd/system/phptest.socket

[Unit]
Description=Test socket

[Socket]
ListenStream=0.0.0.0:8888

[Install]
WantedBy=sockets.target

/etc/systemd/system/phptest.service

[Unit]
Description=php test
After=network.service

[Service]
Type=simple
WorkingDirectory=/root
ExecStart=/usr/bin/php /root/test.php
Restart=always
RestartSec=5
StandardInput=socket
StandardOutput=socket

[Install]
WantedBy=multi-user.target

And here is /root/test.php:

<?php
set_time_limit(0);
while (1)
{
	$in = fread(STDIN,1000);
	echo $in;
	file_put_contents('test.log', $in, FILE_APPEND);
}

If you run it from the shell: "php /root/test.php", it will echo back anything you type. But when it's started by systemd, it doesn't seem to read anything on stdin.

From what I understand, with these service+socket files, anything that is received through the socket should be sent to the program's stdin..?
Thanks,

Vincent

Offline

#2 2016-01-21 17:03:32

gv
Member
Registered: 2016-01-20
Posts: 3

Re: Systemd socket files stdin redirection

Ok I think I have found my problem. Listing  /proc/[pid]/fd shows that the process started by systemd is connected to the listening socket instead of the established connection.
I was expecting the system to pool all input from all connections and send it to the stdin of the service (and vice-versa for stdout; send a copy of the output to all connected sockets). I know it's a bit of a stretch, but it's not clear in the systemd docs what happens. It just says that the "StandardInput=socket" option will redirect the socket's input to the service's stdin.

In case it helps someone, to make that work, you need to add the "Accept=true" parameter in the socket config file. You also need to create a matching "phptest@.service" file (exactly the same contents like the phptest.service file in my initial example, just add an '@' to its name to tell systemd that it's a template and that multiple instances can be run at once).
The default setting for "Accept" is false, and seems to be only used when you need to start a service remotely (honestly I can't think of many situations when that would be useful.. Unless there actually is a way for the service to connect to the established socket?)

Now when I connect on the port (I just telnet to it), anything I type is correctly echoed back. And listing  /proc/[pid]/fd shows that its stdin/out are connected to the correct socket.
It's not exactly what I wanted though, because the service I need to run must have only a single instance running. It can be limited with the "MaxConnections" parameter, but the process will still be killed as soon as the user disconnects from the tcp stream, so it's not a solution either..
I usually have a simple daemon listening on a port and pooling all input and sending it to a service. When I stumbled upon systemd sockets yesterday, i thought I had found a simple and easier solution.. oh well.. wink

For anyone who wants to try, this works:

/etc/systemd/system/phptest.socket

[Unit]
Description=Test socket

[Socket]
ListenStream=0.0.0.0:8888
Accept=true

[Install]
WantedBy=sockets.target

/etc/systemd/system/phptest@.service

[Unit]
Description=php test
After=network.service

[Service]
Type=simple
WorkingDirectory=/root
ExecStart=/usr/bin/php /root/test.php
Restart=always
RestartSec=5
StandardInput=socket
StandardOutput=socket

[Install]
WantedBy=multi-user.target

Last edited by gv (2016-01-21 17:05:14)

Offline

#3 2016-01-22 14:13:25

gv
Member
Registered: 2016-01-20
Posts: 3

Re: Systemd socket files stdin redirection

Looks like it is possible for the service to read/write on the socket without using the "Accept" parameter, but it has to support sd_listen_fds

Offline

Board footer

Powered by FluxBB