fix: sideband UDP — socket AF_INET6 automatique si JETSON_HOST est IPv6

Le socket était créé en AF_INET, bloquant tout envoi vers une adresse
Mycelium IPv6. _udp_sock() détecte le type d'adresse via ipaddress et
choisit AF_INET6 (4-tuple) ou AF_INET selon JETSON_HOST.
Gère aussi le changement de host à chaud via POST /settings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 16:49:23 +02:00
parent ec6db004a9
commit cdd3fa6965

View File

@ -9,6 +9,7 @@ Encoder strategy: v4l2h264enc hardware (default) → x264enc software (auto-fall
Config: .env (base) overridden by .env.dev if present Config: .env (base) overridden by .env.dev if present
""" """
import ipaddress
import json import json
import os import os
import shlex import shlex
@ -140,12 +141,30 @@ def _build_pipeline(cfg: dict, encoder: str) -> str:
# --- Sideband UDP thread ------------------------------------------------------ # --- Sideband UDP thread ------------------------------------------------------
def _udp_sock(host: str) -> tuple:
"""Return (socket, is_ipv6) with the right address family for host."""
try:
is_ipv6 = isinstance(ipaddress.ip_address(host), ipaddress.IPv6Address)
except ValueError:
is_ipv6 = False
family = socket.AF_INET6 if is_ipv6 else socket.AF_INET
return socket.socket(family, socket.SOCK_DGRAM), is_ipv6
def _sideband_worker(gst: "GstManager") -> None: def _sideband_worker(gst: "GstManager") -> None:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) init_cfg = gst.get_cfg()
log.info("Sideband UDP ready (→ port %d)", SIDEBAND_PORT) sock, is_ipv6 = _udp_sock(init_cfg["jetson_host"])
current_host = init_cfg["jetson_host"]
log.info("Sideband UDP ready (→ %s port %d)", "IPv6" if is_ipv6 else "IPv4", SIDEBAND_PORT)
try: try:
while not gst._shutdown.is_set(): while not gst._shutdown.is_set():
cfg = gst.get_cfg() cfg = gst.get_cfg()
host = cfg["jetson_host"]
if host != current_host:
sock.close()
sock, is_ipv6 = _udp_sock(host)
current_host = host
log.info("Sideband socket recreated for new host %s (%s)", host, "IPv6" if is_ipv6 else "IPv4")
cpu_pct = _get_cpu_pct() # blocks 0.5 s internally cpu_pct = _get_cpu_pct() # blocks 0.5 s internally
temp = _get_temp_celsius() temp = _get_temp_celsius()
throttled = _get_throttled() throttled = _get_throttled()
@ -161,8 +180,9 @@ def _sideband_worker(gst: "GstManager") -> None:
"throttled": throttled, "throttled": throttled,
"uptime_s": int(time.time() - START_TIME), "uptime_s": int(time.time() - START_TIME),
}).encode() }).encode()
addr = (host, SIDEBAND_PORT, 0, 0) if is_ipv6 else (host, SIDEBAND_PORT)
try: try:
sock.sendto(payload, (cfg["jetson_host"], SIDEBAND_PORT)) sock.sendto(payload, addr)
except OSError as exc: except OSError as exc:
log.debug("sideband send: %s", exc) log.debug("sideband send: %s", exc)
time.sleep(0.5) # 0.5 s cpu read + 0.5 s sleep ≈ 1 Hz time.sleep(0.5) # 0.5 s cpu read + 0.5 s sleep ≈ 1 Hz