mirror of
https://github.com/wangyu-/UDPspeeder.git
synced 2025-11-26 22:55:37 +08:00
Add systemd socket activation capability
Add support for a systemd.socket activation. Socket it passed from
systemd via file descriptor (see systemd.socket doc)
Also, added a few features for convenience:
* --conn/conv-timeout options to control conversation and connection
timeouts
* --shutdown option to shutdown service after all connections are
timeouted. This is for convent usage with systemd.socket
* test script which allows to smoke test udp speeder and its
socket activation capability
* example systemd unit files
This commit is contained in:
62
test/README.md
Normal file
62
test/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
Testing UDP speeder
|
||||
---
|
||||
|
||||
### Build
|
||||
```
|
||||
export UDP_SPEEDER_REPO=<path to UPDspeeder repo>
|
||||
make -C ${UDP_SPEEDER_REPO}
|
||||
```
|
||||
|
||||
### Simple test
|
||||
```
|
||||
# Start server
|
||||
python3 ${UDP_SPEEDER_REPO}/test/udp_speeder_test.py \
|
||||
--speederv2-path ${UDP_SPEEDER_REPO}/speederv2 \
|
||||
--mode server \
|
||||
--extra-args "--conn-timeout 20 --conv-timeout 10" \
|
||||
--log-level info
|
||||
|
||||
# Start client
|
||||
python3 ${UDP_SPEEDER_REPO}/test/udp_speeder_test.py \
|
||||
--speederv2-path ${UDP_SPEEDER_REPO}/UDPspeeder/speederv2 \
|
||||
--mode client \
|
||||
--log-level info
|
||||
```
|
||||
|
||||
### Test with systemd-socket-activate
|
||||
```
|
||||
# Start server with --socket-activate
|
||||
python3 ${UDP_SPEEDER_REPO}/test/udp_speeder_test.py \
|
||||
--speederv2-path ${UDP_SPEEDER_REPO}/speederv2 \
|
||||
--mode server \
|
||||
--socket-activate \
|
||||
--extra-args "--conn-timeout 20 --conv-timeout 10" \
|
||||
--log-level info
|
||||
|
||||
#Start client
|
||||
```
|
||||
|
||||
### Test with real systemd units
|
||||
```
|
||||
# Add unit files
|
||||
sudo ln -s ${UDP_SPEEDER_REPO}/test/udp_speeder.socket /etc/systemd/system/
|
||||
sudo ln -s ${UDP_SPEEDER_REPO}/test/udp_speeder.service /etc/systemd/system/
|
||||
|
||||
# Enable them to systemd
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable udp_speeder.socket
|
||||
sudo systemctl enable udp_speeder.socket
|
||||
|
||||
# Observe status and logs
|
||||
sudo systemctl status udp_speeder.socket
|
||||
journalctl -f -u udp_speeder.socket -u udp_speeder.service
|
||||
|
||||
# Start test server without speederv2 (will be started by udp_speeder.socket)
|
||||
python3 ${UDP_SPEEDER_REPO}/test/udp_speeder_test.py \
|
||||
--mode server \
|
||||
--no-udpspeeder \
|
||||
--log-level info
|
||||
|
||||
# Start client
|
||||
```
|
||||
|
||||
133
test/udp_speeder_test.py
Normal file
133
test/udp_speeder_test.py
Normal file
@@ -0,0 +1,133 @@
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import signal
|
||||
import time
|
||||
import argparse
|
||||
|
||||
LOG_LEVEL_MAP = {
|
||||
"never": 0,
|
||||
"fatal": 1,
|
||||
"error": 2,
|
||||
"warn": 3,
|
||||
"info": 4,
|
||||
"debug": 5,
|
||||
"trace": 6
|
||||
}
|
||||
|
||||
class UDPspeederTest:
|
||||
def __init__(self, speederv2_path, log_level="info", socket_activate=False, extra_udpspeeder_args="", no_udpspeeder=False):
|
||||
self.speederv2_path = speederv2_path
|
||||
self.log_level = log_level
|
||||
self.socket_activate = socket_activate
|
||||
self.extra_udpspeeder_args = extra_udpspeeder_args
|
||||
self.no_udpspeeder = no_udpspeeder
|
||||
|
||||
def run_speederv2(self, mode, local_port, remote_ip, remote_port):
|
||||
log_level_num = LOG_LEVEL_MAP.get(self.log_level, 4) # Default to "info" if log_level is not found
|
||||
cmd = f"{self.speederv2_path} {mode} -l0.0.0.0:{local_port} -r{remote_ip}:{remote_port} -f20:10 --log-level {log_level_num} {self.extra_udpspeeder_args}"
|
||||
if self.socket_activate:
|
||||
cmd = f"systemd-socket-activate -l0.0.0.0:{local_port} -d {cmd}"
|
||||
print(f"UPDspeeder command: {cmd}")
|
||||
|
||||
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
return process
|
||||
|
||||
def start_udpspeeder_server(self, local_port, remote_port):
|
||||
return self.run_speederv2("-s", local_port, "127.0.0.1", remote_port)
|
||||
|
||||
def start_udpspeeder_client(self, local_port, remote_ip, remote_port):
|
||||
return self.run_speederv2("-c", local_port, remote_ip, remote_port)
|
||||
|
||||
def server(self, udp_speeder_port, server_port):
|
||||
# Start UDPspeeder server if not disabled
|
||||
if not self.no_udpspeeder:
|
||||
udpspeeder_process = self.start_udpspeeder_server(udp_speeder_port, server_port)
|
||||
threading.Thread(target=self.log_udpspeeder_output, args=(udpspeeder_process,)).start()
|
||||
|
||||
# Start UDP server
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("0.0.0.0", server_port))
|
||||
print(f"Server listening on port {server_port}")
|
||||
|
||||
def cleanup(signum, frame):
|
||||
print("Shutting down server...")
|
||||
sock.close()
|
||||
if not self.no_udpspeeder:
|
||||
udpspeeder_process.terminate()
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGTERM, cleanup)
|
||||
|
||||
while True:
|
||||
data, addr = sock.recvfrom(1024)
|
||||
print(f"Received message: {data.decode()} from {addr}")
|
||||
reply = f"Server reply to {data.decode()}"
|
||||
sock.sendto(reply.encode(), addr)
|
||||
print(f"Sent reply: {reply} ==============================================================")
|
||||
|
||||
def client(self, us_client_port, us_server_port):
|
||||
# Start UDPspeeder client if not disabled
|
||||
if not self.no_udpspeeder:
|
||||
udpspeeder_process = self.start_udpspeeder_client(us_client_port, "127.0.0.1", us_server_port)
|
||||
threading.Thread(target=self.log_udpspeeder_output, args=(udpspeeder_process,)).start()
|
||||
|
||||
# Start UDP client
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
server_address = ("127.0.0.1", us_client_port)
|
||||
message = "Hello, Server!"
|
||||
|
||||
def cleanup(signum, frame):
|
||||
print("Shutting down client...")
|
||||
sock.close()
|
||||
if not self.no_udpspeeder:
|
||||
udpspeeder_process.terminate()
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGTERM, cleanup)
|
||||
sock.settimeout(1.0)
|
||||
|
||||
while True:
|
||||
print(f"Sending message: {message}")
|
||||
sent = sock.sendto(message.encode(), server_address)
|
||||
|
||||
try:
|
||||
data, server = sock.recvfrom(1024)
|
||||
except socket.timeout:
|
||||
print("Request timed out")
|
||||
continue
|
||||
|
||||
print(f"Received reply: {data.decode()} ==============================================================")
|
||||
time.sleep(1)
|
||||
|
||||
sock.close()
|
||||
|
||||
def log_udpspeeder_output(self, process):
|
||||
for line in process.stdout:
|
||||
print(line.decode(), end='')
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="UDPspeeder test script")
|
||||
parser.add_argument("--mode", choices=["server", "client"], help="Mode to run: 'server' or 'client'")
|
||||
parser.add_argument("--us-server-port", type=int, default=4096, help="UDPspeeder server port")
|
||||
parser.add_argument("--us-client-port", type=int, default=3333, help="UDPspeeder client port")
|
||||
parser.add_argument("--server-port", type=int, default=7777, help="Server port behind UDPspeeder")
|
||||
parser.add_argument("--log-level", choices=LOG_LEVEL_MAP.keys(), default="info", nargs="?", help="Log level: 'never', 'fatal', 'error', 'warn', 'info', 'debug', 'trace'")
|
||||
parser.add_argument("--socket-activate", action="store_true", help="Test systemd socket activation")
|
||||
parser.add_argument("--extra-args", help="Extra arguments to pass to UDPspeeder")
|
||||
parser.add_argument("--no-udpspeeder", action="store_true", help="Do not start UDPspeeder")
|
||||
parser.add_argument("--speederv2-path", default="speederv2", help="Path to the speederv2 binary")
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
udpspeeder_test = UDPspeederTest(args.speederv2_path, args.log_level, args.socket_activate, args.extra_args, args.no_udpspeeder)
|
||||
|
||||
if args.mode == "server":
|
||||
udpspeeder_test.server(args.us_server_port, args.server_port)
|
||||
elif args.mode == "client":
|
||||
udpspeeder_test.client(args.us_client_port, args.us_server_port)
|
||||
else:
|
||||
print("Invalid mode. Use 'server' or 'client'.")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user