From 5399e1d4633e43e522185e2113018a5482ff11ab Mon Sep 17 00:00:00 2001 From: Kroese Date: Sat, 18 Jul 2026 11:31:20 +0200 Subject: [PATCH] feat: Use Unix sockets for qemu-host communication (#1299) --- docs/environment.md | 2 -- src/power.sh | 7 ++++--- src/print.sh | 5 +++-- src/serial.sh | 41 +++++++++++++++++++++++++++-------------- src/server.sh | 4 ---- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/docs/environment.md b/docs/environment.md index 028a4dc..743fb7f 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -95,6 +95,4 @@ An empty default means the variable is unset and its value is determined automat |---|---|---| | `DEBUG` | `N` | Enables verbose debug output. | | `TRACE` | `N` | Enables shell command tracing. | -| `COM_PORT` | `2210` | Internal communication port used by the DSM host helper. | -| `CHR_PORT` | `12345` | Internal character device port used by the DSM host helper. | | `HOST_DEBUG` | `N` | Enables debug output for the DSM host helper. | diff --git a/src/power.sh b/src/power.sh index 222e861..8c8b216 100644 --- a/src/power.sh +++ b/src/power.sh @@ -8,7 +8,6 @@ set -Eeuo pipefail # Configure QEMU for graceful shutdown API_CMD=6 -API_HOST="127.0.0.1:$COM_PORT" SHUTDOWN_SKIP=0 SHUTDOWN_SIGNAL=0 @@ -98,6 +97,8 @@ cleanupHelpers() { mKill "${pids[@]}" fKill "print.sh" + rm -f -- "$HOST_API_SOCKET" "$HOST_AGENT_SOCKET" + closeNetwork return 0 } @@ -191,8 +192,8 @@ sendGuestShutdown() { # Send shutdown command to guest agent via serial port API_TIMEOUT=$(strip "$API_TIMEOUT") - url="http://$API_HOST/read?command=$API_CMD&timeout=$API_TIMEOUT" - response=$(curl -sk -m "$(( API_TIMEOUT+2 ))" -S "$url" 2>&1) + url="http://localhost/read?command=$API_CMD&timeout=$API_TIMEOUT" + response=$(curl --unix-socket "$HOST_API_SOCKET" -sk -m "$(( API_TIMEOUT+2 ))" -S "$url" 2>&1) if [[ "$response" =~ "\"success\"" ]]; then diff --git a/src/print.sh b/src/print.sh index 03621f5..3b2f502 100644 --- a/src/print.sh +++ b/src/print.sh @@ -19,8 +19,9 @@ driver="/run/shm/qemu.nic" page="/run/shm/index.html" address="/run/shm/qemu.ip" shutdown="/run/shm/qemu.end" +socket="/run/shm/qemu-host-api.sock" template="/var/www/index.html" -url="http://127.0.0.1:2210/read?command=10" +url="http://localhost/read?command=10" resp_err="Guest returned an invalid response:" curl_err="Failed to connect to guest: curl error" @@ -37,7 +38,7 @@ queryGuest() { local rc - { json=$(curl -m 20 -sk "$url"); rc=$?; } || : + { json=$(curl --unix-socket "$socket" -m 20 -sk "$url"); rc=$?; } || : exitIfShuttingDown diff --git a/src/serial.sh b/src/serial.sh index 5a2a078..7ea3ddc 100644 --- a/src/serial.sh +++ b/src/serial.sh @@ -15,6 +15,10 @@ HOST_MODEL=$(strip "$HOST_MODEL") HOST_SERIAL=$(strip "$HOST_SERIAL") GUEST_SERIAL=$(strip "$GUEST_SERIAL") +HOST_PID="$QEMU_DIR/host.pid" +HOST_API_SOCKET="$QEMU_DIR/qemu-host-api.sock" +HOST_AGENT_SOCKET="$QEMU_DIR/qemu-host-agent.sock" + validateHostMac() { local m @@ -41,6 +45,8 @@ buildHostArguments() { HOST_ARGS=() HOST_ARGS+=("-cpu=$CPU_CORES") HOST_ARGS+=("-cpu_arch=$HOST_CPU") + HOST_ARGS+=("-api=$HOST_API_SOCKET") + HOST_ARGS+=("-addr=$HOST_AGENT_SOCKET") [ -n "$HOST_MAC" ] && HOST_ARGS+=("-mac=$HOST_MAC") [ -n "$HOST_MODEL" ] && HOST_ARGS+=("-model=$HOST_MODEL") @@ -54,6 +60,8 @@ startHostBinary() { local pid + rm -f -- "$HOST_PID" "$HOST_API_SOCKET" "$HOST_AGENT_SOCKET" || return 1 + if enabled "$HOST_DEBUG"; then set -x ./host.bin "${HOST_ARGS[@]}" & @@ -70,17 +78,27 @@ startHostBinary() { return 0 } +waitForSocket() { -waitForPort() { - - local port="$1" + local socket="$1" local exit_code="$2" - local cnt=0 + local pid cnt=0 + + while [ ! -S "$socket" ]; do + + if ! read -r pid < "$HOST_PID" || ! isAlive "$pid"; then + error "qemu-host exited unexpectedly!" + exit "$exit_code" + fi - while ! nc -z -w2 127.0.0.1 "$port" > /dev/null 2>&1; do sleep 0.1 cnt=$((cnt + 1)) - (( cnt > 50 )) && error "Failed to connect to qemu-host.." && exit "$exit_code" + + if (( cnt > 50 )); then + error "Failed to create qemu-host socket: $socket" + exit "$exit_code" + fi + done return 0 @@ -106,24 +124,19 @@ configureSerialPorts() { SERIAL_OPTS+=" \ -device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \ - -chardev socket,id=charchannel0,host=127.0.0.1,port=$CHR_PORT,reconnect=10 \ + -chardev socket,id=charchannel0,path=$HOST_AGENT_SOCKET,reconnect-ms=1000 \ -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=vchannel" return 0 - } validateHostMac -HOST_PID="$QEMU_DIR/host.pid" - buildHostArguments startHostBinary -sleep 0.2 - -waitForPort "$COM_PORT" 58 -waitForPort "$CHR_PORT" 59 +waitForSocket "$HOST_API_SOCKET" 58 +waitForSocket "$HOST_AGENT_SOCKET" 59 configureSerialPorts diff --git a/src/server.sh b/src/server.sh index ab1034a..508156e 100644 --- a/src/server.sh +++ b/src/server.sh @@ -1,15 +1,11 @@ #!/usr/bin/env bash set -Eeuo pipefail -: "${COM_PORT:="2210"}" # Comm port : "${WEB_PORT:="5000"}" # Webserver port -: "${CHR_PORT:="12345"}" # Character port : "${WSD_PORT:="8004"}" # Websockets port # Sanitize port variables -COM_PORT=$(strip "$COM_PORT") WEB_PORT=$(strip "$WEB_PORT") -CHR_PORT=$(strip "$CHR_PORT") WSD_PORT=$(strip "$WSD_PORT") WEB_PID="/run/nginx.pid"