0

I have a simple socket/service pair where the service relies on stdin from the socket:

# /etc/systemd/system/simple.socket
[Unit]
Description=Simple socket

[Socket]
ListenStream=11111
# /etc/systemd/system/simple.service
[Unit]
Description=Simple service

[Service]
Type=simple
ExecStart=-cat -
StandardInput=socket
StandardOutput=socket

When I try to launch with netcat 127.0.0.1 11111 I get:

- simple.service - "Simple service"
     Loaded: loaded (/etc/systemd/system/simple.service; vendor preset: enabled)
     Active: failed (Result: start-limit-hit) since Tue 2020-05-19 09:42:17 CEST; 11min ago
TriggeredBy: simple.socket
    Process: 400879 ExecStart=/bin/cat - (code=exited, status=1/FAILURE)
   Main PID: 400879 (code=exited, status=1/FAILURE)

- simple.socket - "Simple socket"
     Loaded: loaded (/etc/systemd/system/simple.socket; static; vendor preset: enabled)
     Active: failed (Result: service-start-limit-hit) since Tue 2020-05-19 09:42:17 CEST; 11min ago
   Triggers: simple.service
     Listen: [::]:11111 (Stream)

My guess is that cat is failing to start because it is trying to connect to stdin which is not available. If I replace cat - with sleep infinity the service starts fine. I can't figure out why

0

The solution has to do with the Accept= option of a socket.

This version will work:

# /etc/systemd/system/simple.socket
[Unit]
Description=Simple socket

[Socket]
Accept=yes
ListenStream=11111

Note the new filepath

# /etc/systemd/system/simple@.service
[Unit]
Description=Simple service

[Service]
Type=simple
ExecStart=-cat -
StandardInput=socket
StandardOutput=socket

Now nc 127.0.0.1 11111 does not return and lets you echo back whatever you send. Also systemctl status simple* now gives:

- simple.socket - Simple socket
     Loaded: loaded /etc/systemd/system/simple.socket; static: vendor preset: enabled)
     Active: active (listening) since Tue 2020-05-19 10:04:48 CEST; 48s ago
   Triggers: simple@1-127.0.0.1:11111-127.0.0.1:47194.service
     Listen: [::]:11111 (Stream)
   Accepted: 2; Connected: 1;
      Tasks: 0 (limit: 9429)
     Memory: 120.0K
     CGroup: /system.slice/simple.socket

- simple@1-127.0.0.1:11111-127.0.0.1:47194.service - "Simple service" (127.0.0.1:47194)
     Loaded: loaded /etc/systemd/system/simple@.service; static: vendor preset: enabled)
     Active: active (running) since Tue 2020-05-19 10:04:48 CEST; 48s ago
TriggeredBy: simple.socket
   Main PID: 403830 (cat)
      Tasks: 1 (limit: 9429)
     Memory: 184.0K
     CGroup: /system.slice/system-simple.slice/simple@1-127.0.0.1:11111-127.0.0.1:47194.service
             -403830 /bin/cat -

I assume this works because when Accept=no, each connection tries to connect to the same process, and it's a bit strange trying to mux several sockets into a single stdin. With Accept=yes each connection spawns a new process and so it's simple to simply pipe the socket into the stdin of each process.

1
  • Your assumption is wrong. The correct answer is that cat does not call accept() and so isn't compatible with being passed a listening socket as its standard input.
    – JdeBP
    May 19 '20 at 12:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.