Files
OpenFUT/fifa17-recon/docker/fifa17-python/entrypoint.sh
T
2026-08-21 02:35:27 +00:00

121 lines
5.2 KiB
Bash

#!/usr/bin/env bash
# ============================================================================
# OpenFUT FIFA-17 FUT backend — in-CONTAINER orchestrator.
#
# Runs the 5 network responders that the game dials. Unlike the host-based
# openfut-fut.sh, this does NO host arming (no pkexec / iptables / /etc/hosts /
# ptrace) — those are client-side concerns handled on the game machine (105).
# autopatch.py is NOT run here: it patches the FIFA17.exe process memory and must
# run on the box the game runs on.
#
# Address behaviour is driven by three env vars (see each responder):
# OPENFUT_BIND bind address for every listener (container: 0.0.0.0)
# OPENFUT_ADVERTISE IP address handed out for Blaze, UTAS, telemetry, and QoS
# OPENFUT_ROSTER_HOST certificate DNS host:port handed out for roster HTTPS
# ============================================================================
set -uo pipefail
cd "$(dirname "$(readlink -f "$0")")/tools"
BIND="${OPENFUT_BIND:-0.0.0.0}"
ADV="${OPENFUT_ADVERTISE:?OPENFUT_ADVERTISE must be set to the server LAN IP (e.g. 203.0.113.10)}"
ROSTER_HOST="${OPENFUT_ROSTER_HOST:-winter15.gosredirector.ea.com:8081}"
export OPENFUT_BIND="$BIND"
export OPENFUT_ADVERTISE="$ADV"
export OPENFUT_ROSTER_HOST="$ROSTER_HOST"
# POW keys advertised by blaze must also point at the server, not loopback.
export POW_HOST="${POW_HOST:-$ADV:8094}"
export POW_CONTENT_HOST="${POW_CONTENT_HOST:-$ADV:8080}"
export POW_ADDR="${POW_ADDR:-$BIND:8094}"
export POW_CONTENT_ADDR="${POW_CONTENT_ADDR:-$BIND:8080}"
echo "[openfut] bind=$BIND advertise=$ADV roster=$ROSTER_HOST"
# FIFA17's roster verifier compares only dNSName SAN entries. It ignores a valid
# iPAddress SAN when the advertised URL contains an IP literal, so certificate
# regeneration cannot fix that URL. Keep the certificate stable and fail startup
# if the configured roster hostname is not already one of its DNS identities.
CERT=redir_cert.pem
ROSTER_NAME="${ROSTER_HOST%%:*}"
if ! openssl x509 -in "$CERT" -noout -checkhost "$ROSTER_NAME" >/dev/null 2>&1; then
echo "[openfut] FATAL: TLS cert does not cover roster hostname $ROSTER_NAME" >&2
exit 1
fi
echo "[openfut] roster certificate matches $ROSTER_NAME; fingerprint: $(openssl x509 -in "$CERT" -noout -fingerprint -sha256)"
# name script extra-env
declare -a SERVERS=(
"lsx|lsx_responder_v2.py|OPENFUT_LSX_EVENT_COUNT=100000"
"blaze|blaze_responder_v3b.py|-"
"roster|roster_server.py|-"
"utas|utas_server.py|FUT_TRADING=1 FUT_PILESIZES=1 FUT_TRADEABLE=1 FUT_DISCARD_TABLE=1 FUT_DISCARD_SEND=1"
"pow|pow_server.py|-"
)
# ── Component selection ──────────────────────────────────────────────────────
# OPENFUT_SERVERS picks which Python responders run (space- or comma-separated).
# This container is the SERVER side (.120). It serves ONLY components that have
# NOT been migrated to a Rust host — as each moves to Rust (which runs OUTSIDE
# Docker during migration), drop its name so the two never serve the same role.
# blaze Blaze redirector + main + nucleus (bundled) :42127 :42130 :42131
# roster FUT roster-update XML :8081
# utas FUT/UTAS RS4 API :8099
# (the Rust utas-host currently reverse-proxies its non-/club routes
# back here, so keep this enabled until UTAS is fully migrated)
# pow POW / EASFC :8094 (+ content :8080)
# lsx Origin LSX bootstrap :4216
# CLIENT-SIDE — LSX runs on the game machine (.105) with autopatch,
# NOT on the server. Excluded by default; enable ONLY for an
# all-on-one-box dev setup where client and server share a host.
OPENFUT_SERVERS="${OPENFUT_SERVERS:-blaze roster utas pow}"
want=" ${OPENFUT_SERVERS//,/ } "
known=" lsx blaze roster utas pow "
for w in $want; do
case "$known" in
*" $w "*) ;;
*) echo "[openfut] unknown component '$w' in OPENFUT_SERVERS (valid: lsx blaze roster utas pow)" >&2; exit 2 ;;
esac
done
echo "[openfut] servers=$OPENFUT_SERVERS"
pids=()
names=()
for entry in "${SERVERS[@]}"; do
IFS='|' read -r name script env <<<"$entry"
case "$want" in
*" $name "*) ;;
*) echo "[openfut] skipping $name (not in OPENFUT_SERVERS)"; continue ;;
esac
envprefix=""; [ "$env" != "-" ] && envprefix="env $env"
echo "[openfut] starting $name ($script)"
# shellcheck disable=SC2086
$envprefix python3 -u "$script" &
pids+=($!)
names+=("$name")
done
if [ "${#pids[@]}" -eq 0 ]; then
echo "[openfut] OPENFUT_SERVERS selected no components; nothing to run" >&2
exit 2
fi
# Propagate SIGTERM/SIGINT to children so `docker stop` is clean.
term() {
echo "[openfut] shutting down…"
for p in "${pids[@]}"; do kill "$p" 2>/dev/null || true; done
wait
exit 0
}
trap term TERM INT
# If ANY responder dies, take the whole container down so the failure is visible
# (they all bind ports the game needs — a partial stack is a broken stack).
while true; do
for i in "${!pids[@]}"; do
if ! kill -0 "${pids[$i]}" 2>/dev/null; then
echo "[openfut] responder ${names[$i]} (pid ${pids[$i]}) exited - bringing container down"
term
fi
done
sleep 2
done