An adsb-centric example to run a socket service via systemd.
Combing multiple dump1090 and dump978 feeders was historically a task for cron
and keepalive scripts using ncat
or socat
.
With my SDR receivers in different windows for maximum coverage, I would use ncat
to connect different input and output ports to feed the central server running as --net-only
. dump978
adds a complication as it only outputs UAT downlink messages and our map expects ADS-B ES/NT messages.
Aggregation to the primary dump1090
map was handled with cron
via:
#!/bin/bash
# test 1090 receivers are forwarding
# runs via cron @reboot and a few times an hour for reliability
for receiver in pizero pi3
do
#echo "testing $receiver"
ps -ef |grep "TCP\:$receiver\:30005" > /dev/null
if [ $? != 0 ]
then
echo "restarting 1090 $receiver"
socat -u TCP:$receiver:30005 TCP:localhost:30004 &
# original netcat way
# #ncat --recv-only $receiver 30005 | ncat --send-only localhost 30004 &
fi
done
# 978 receiver (more complicated with uat2esnt)
for receiver in pizero
do
#echo "checking $receiver"
pgrep -a 'ncat' | grep "$receiver 20002" > /dev/null
if [ $? != 0 ]
then
echo "restarting 978 $receiver"
ncat --recv-only $receiver 20002 | /path/to/git/dump978/uat2esnt | ncat --send-only localhost 30001 &
fi
done
So I finally stopped worrying and learned to love the systemd. Reading Pid Eins was helpful. The uat2esnt
situation sounded like a good case for a socket service. This will consist of a uat2esnt.socket
and uat2esnt@.service
.
uat2esnt.socket
[Unit]
Description = dump978 uat2esnt conversion service
[Socket]
ListenStream = 40404
Accept = yes
[Install]
WantedBy = sockets.target
uat2esnt@.service
[Unit]
Description = dump978 uat2esnt conversion service
[Service]
#User=dump1090
ExecStart=/path/to/git/dump978/uat2esnt
StandardInput=socket
StandardOutput=socket
SyslogIdentifier=uat2esnt
Type=simple
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target
Link or copy these to /etc/systemd/system/
and systemctl start uat2esnt.socket
.
Now you can test this by connecting to port 40404 and feeding it some UAT messages and see the raw translated message.
socat - TCP:localhost:40404
sample data to paste:
-00ad723335ade35230d4065900941d813800;rs=1;
-08a04568350889526cb40b7911e81100b806431335ed2d0b62a4c0a0000c00000000;
-08ad723335adf55230fc0669008c1e815807ae2094e6c40b42a4c2800006c0000000;rs=5;
-00a0456835083f526cce0b7911e81180b800;
-10a0456835082b526cd40b8911e81180ce0000000000000000000000000c00000000;
-00a045683507d7526cf20b8911e41180bf00;
-00a045683507c3526cfa0b9911e41200b800;
-08a0456835078f526d0c0b9911e41200b909d9073469c40b96a4c2a0000c20000000;
You should see the ADS-B ES/NT messages coded as replies in the terminal.
Great! It processes messages but I'm feeding other services. Fixing this, remove the StandardOutput=
line and change the ExecStart=
line to feed my 1090 receiver and make sure that service is running with an After=dump1090.service
in the [Unit]
section.
As a gotcha, systemd doesn't support pipes in the ExecStart=
so I pass a shell command as an argument hack.
ExecStart=/usr/bin/sh -c '/path/to/git/dump978/uat2esnt | socat -u STDIN TCP:localhost:30001'
. When you've done this, systemctl daemon-reload
is your friend to test the changes.
Upstream, the UAT 978 receiver still needs to send the messages to HQ.
socat978@.service
:
[Unit]
Description=dump978 feed from a %I to dump1090
Wants=network.target
After=network.target dump1090.service uat2esnt.socket
[Service]
User=dump1090
ExecStart=socat -u TCP:%i:20002 TCP:localhost:40404
SyslogIdentifier=socat978
Type=simple
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target
This script can be setup to feed from multiple hosts ala systemctl start socat978@hostname
.
Don't forget to systemctl enable
your services to persist when you have everything working.
sh -c
hack for the pipe in systemd