#!/bin/bash # Does port allocation avoid a port the HOST is already listening on? # # scripts/dev/lp-port-host-test # # It used to avoid only a hardcoded list (8080, 6060) plus whatever an admin had # written into CFG_RESERVED_PORTS_EXTRA, while the comment above it claimed a # picked port "can never collide with a host service at compose-up time". On a # desktop, a first-run restore handed stoat's livekit a UDP port kdeconnectd # already held; compose failed with "address already in use", four dependent # containers exited 101, and the app came back half-running under a restore that # reported success. # # The test binds a real socket and asserts the allocator refuses that port. REPO="$(cd "$(dirname "$0")/../.." && pwd)" fail=0 chk(){ if [[ "$2" == "$3" ]]; then echo " ok $1"; else echo " FAIL $1: got '$2' want '$3'"; fail=1; fi; } command -v ss >/dev/null 2>&1 || { echo " SKIP ss not available"; exit 0; } # Hold a real port for the duration, so this tests the kernel's answer and not a # fixture's idea of one. python3 -c ' import socket, sys, time s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(("127.0.0.1", 0)); s.listen(1) print(s.getsockname()[1], flush=True) time.sleep(30) ' > /tmp/lp-port-host-test.$$ & holder=$! trap 'kill $holder 2>/dev/null; rm -f /tmp/lp-port-host-test.$$' EXIT for _ in $(seq 1 50); do [[ -s /tmp/lp-port-host-test.$$ ]] && break; sleep 0.1; done BOUND=$(cat /tmp/lp-port-host-test.$$) [[ -n "$BOUND" ]] || { echo " FAIL could not bind a test port"; exit 1; } echo "--- holding tcp/$BOUND ---" source "$REPO/scripts/network/ports/core/port_find_next_available.sh" echo "--- the kernel's view includes it ---" chk "in host set" "$(portHostBoundPorts | grep -cx "$BOUND")" "1" echo "--- allocation refuses it ---" # A one-port range containing only the bound port: with no other candidate, a # correct allocator returns nothing rather than handing back a port in use. isNotice(){ :; }; isError(){ :; } runInstallOp(){ :; } # empty => the port table claims nothing docker_dir="/tmp"; db_file="lp-port-host-test.db.$$"; : > "$docker_dir/$db_file" CFG_PORT_RANGE="$BOUND-$BOUND" CFG_RESERVED_PORTS_EXTRA="" allocated_port="sentinel" portFindNextAvailablePort rm -f "$docker_dir/$db_file" chk "refused the bound port" "$allocated_port" "" echo "--- a free range still allocates ---" CFG_PORT_RANGE="49000-49010" : > "$docker_dir/$db_file" allocated_port="" portFindNextAvailablePort rm -f "$docker_dir/$db_file" if [[ "$allocated_port" =~ ^[0-9]+$ ]] && (( allocated_port >= 49000 && allocated_port <= 49010 )); then echo " ok allocated $allocated_port" else echo " FAIL free range gave '$allocated_port'"; fail=1 fi echo "" if (( fail )); then echo "FAILED"; exit 1; fi echo "All port checks passed."