Code Monkey home page Code Monkey logo

socket-activate-echo's Introduction

socket-activate-echo

An echo server that supports systemd socket activation

family type support
AF_UNIX SOCK_STREAM yes
AF_INET SOCK_STREAM yes
AF_INET6 SOCK_STREAM yes
AF_VSOCK SOCK_STREAM yes
AF_UNIX SOCK_DGRAM yes (but no support for outgoing traffic when run in container because the client socket path on the host is not accessible from within the container)
AF_INET SOCK_DGRAM yes
AF_INET6 SOCK_DGRAM yes

Requirements

  • podman version 3.4.0 (released September 2021) or newer
  • container-selinux version 2.183.0 (released April 2022) or newer

If you are using an older version of container-selinux and it does not work, add --security-opt label=disable to podman run.

Installation

  1. Install socat
    sudo dnf -y install socat
    

About the container image

The container image ghcr.io/eriksjolund/socket-activate-echo is built by the GitHub Actions workflow .github/workflows/publish_container_image.yml from the file ./Containerfile.

Activate an instance of a templated systemd user service

  1. Start the echo server sockets

    git clone https://github.com/eriksjolund/socket-activate-echo.git
    mkdir -p ~/.config/systemd/user
    cp -r socket-activate-echo/systemd/* ~/.config/systemd/user
    systemctl --user daemon-reload
    systemctl --user start [email protected]
    
  2. Run the commands

    $ echo hello | socat - tcp4:127.0.0.1:3000
    hello
    $ echo hello | socat - tcp6:[::1]:3000
    hello
    $ echo hello | socat - udp4:127.0.0.1:3000
    hello
    $ echo hello | socat - udp6:[::1]:3000
    hello
    $ echo hello | socat - unix:$HOME/echo_stream_sock.demo
    hello
    $ echo hello | socat - VSOCK-CONNECT:1:3000
    hello
    
  3. Try establishing an outgoing connection

    $ podman exec -t echo-demo curl https://podman.io
    curl: (6) Could not resolve host: podman.io
    $
    

    (The command-line option --network=none was added to prevent the container from establishing outgoing connections)

Socket activate SOCK_STREAM sockets with systemd-socket-activate

  1. Socket activate the echo server

    systemd-socket-activate -l /tmp/stream.sock \
        -l 4000 -l vsock:4294967295:4000 podman run --rm --name echo2 \
        --network=none ghcr.io/eriksjolund/socket-activate-echo
    

    Instead of VMADDR_CID_ANY (4294967295) we could also have used VMADDR_CID_LOCAL (1), in other words, -l vsock:1:4000 (see man 7 vsock).

  2. In another shell

    $ echo hello | socat - unix:/tmp/stream.sock
    hello
    $ echo hello | socat - tcp4:127.0.0.1:4000
    hello
    $ echo hello | socat - tcp6:[::1]:4000
    hello
    $ echo hello | socat - VSOCK-CONNECT:1:4000
    hello
    
  3. Try establishing an outgoing connection

    $ podman exec -t echo2 curl https://podman.io
    curl: (6) Could not resolve host: podman.io
    $
    

Socket activate SOCK_DGRAM sockets with systemd-socket-activate

  1. Socket activate the echo server

    systemd-socket-activate --datagram \
        -l 5000 podman run --rm --name echo3 \
        --network=none ghcr.io/eriksjolund/socket-activate-echo
    
  2. In another shell

    $ echo hello | socat - udp4:127.0.0.1:5000
    hello
    $ echo hello | socat - udp6:[::1]:5000
    hello
    
  3. Try establishing an outgoing connection

    $ podman exec -t echo3 curl https://podman.io
    curl: (6) Could not resolve host: podman.io
    $
    

Run the echo container inside a VM and connect over AF_VSOCK (SOCK_STREAM)

  1. Install requirements

    sudo dnf install -y qemu butane coreos-installer
    
  2. Start the Fedora CoreOS VM by running these commands on the host

    STREAM=next
    CID=20
    mkdir -p ~/.local/share/libvirt/images/
    file=$(coreos-installer download -s "${STREAM}" -p qemu -f qcow2.xz --decompress -C ~/.local/share/libvirt/images/)
    cat vm/echo.butane | butane --strict --pretty --files-dir systemd > file.ign
    qemu-kvm -m 2048 \
      -device "vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=$CID" \
      -cpu host -nographic -snapshot \
      -drive "if=virtio,file=$file" \
      -fw_cfg name=opt/com.coreos/config,file=file.ign -nic "user,model=virtio"
    

    The Context Identifier (CID) is an arbitrary number that is used to identify the VM (see man vsock).

  3. Run on the host

     $ CID=20
     $ echo hello | socat -t 30 - VSOCK-CONNECT:$CID:3000
     hello
    

Troubleshooting

The container takes long time to start

Pulling a container image may take long time. This delay can be avoided by pulling the container image beforehand and adding the command-line option --pull=never to podman run.

socat times out before receiving the reply

If socat does not receive any reply within a certain time limit it terminates before getting the reply. The timeout is 0.5 seconds by default. Symptoms of this could be

$ systemctl --user start [email protected]
$ echo hello | socat - udp4:127.0.0.1:3000
$ echo hello | socat - udp4:127.0.0.1:3000
hello

To configure the timeout to be 30 seconds, add the command-line option -t 30.

$ echo hello | socat -t 30 - udp4:127.0.0.1:3000
hello

Another way to handle the problem is to use the command-line option readline to get an interactive user interface. Type the word hello and see it being echoed back.

$ socat readline udp4:127.0.0.1:3000
hello
hello

In this case there will be no timeout because none of the channels have reached EOF.

A good way to diagnose problems is to look in the journald log for the service:

journalctl -xe --user -u [email protected]

socket-activate-echo's People

Contributors

eriksjolund avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

socket-activate-echo's Issues

Add support for exiting after some specified time of inactivity

Add support for exiting after some specified time of inactivity.

Specifying

--inactivity-timeout 10

would mean that the program should exit with an exit value of 0 after 10 seconds of inactivity (i.e. 10 seconds of no traffic to or from the echo server).

Depending on the restart configuration for the service (systemd directive Restart), the service
may then be stopped. The socket-activated service would be started again whenever a new client connects.

See also
https://github.com/containers/podman/blob/main/docs/tutorials/socket_activation.md#stopping-a-socket-activated-service

Print the optional file descriptor name from LISTEN_FDNAMES in the debug output

  1. Run the command mkdir -p ~/.config/systemd/user
  2. Create the file ~/.config/systemd/user/echo.socket with this file contents
    [Unit]
    Description=echotest
    [Socket]
    ListenStream=127.0.0.1:9406
    FileDescriptorName=foobar
    
  3. Run the commands
     podman create --rm --name echo --network=none ghcr.io/eriksjolund/socket-activate-echo /socket-activate-echo --debug
     podman generate systemd --name --new echo > ~/.config/systemd/user/echo.service
     systemctl --user daemon-reload
     systemctl --user start echo.socket
     echo hello | socat - tcp4:127.0.0.1:9406
    
  4. Run the journalctl command
    $ journalctl -xe --user -u echo.service CONTAINER_NAME=echo
    Jul 30 17:43:32 asus echo[5596]: Bytes received = 6
    Jul 30 17:43:32 asus echo[5596]: Bytes sent = 6
    

This output is shown

Jul 30 17:43:32 asus echo[5596]: Bytes received = 6
Jul 30 17:43:32 asus echo[5596]: Bytes sent = 6

I would have liked the output to be

Jul 30 17:43:32 asus echo[5596]: bytes received = 6, file descriptor name = "foobar"
Jul 30 17:43:32 asus echo[5596]: bytes sent = 6, file descriptor name = "foobar"

The man page for the function sd_listen_fds_with_names()
has the text
"optionally also returns an array of strings with identification names".
It sounds like the file descriptor name is optional.
Whenever there is no name for the file descriptor print in the same way as before (but lower case the word "Bytes"), i.e.,

Jul 30 17:43:32 asus echo[5596]: bytes received = 6
Jul 30 17:43:32 asus echo[5596]: bytes sent = 6

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.