From a1e5331f4a13d3dd33154d2e74138bc8441c0951 Mon Sep 17 00:00:00 2001 From: Frank Harris Date: Sun, 7 Jun 2026 09:06:49 -0500 Subject: [PATCH] fixed server query --- .../gamemanager/home_handling_functions.php | 7 +- docs/agents/WINDOWS_AGENT.md | 8 +- docs/architecture/API_REFERENCE.md | 9 +- docs/architecture/PANEL_AGENT_COMMANDS.md | 6 +- docs/architecture/RPC_STATUS_REPAIR_REPORT.md | 200 ++++++++++++++++++ docs/features/STATUS_SYSTEM.md | 3 +- docs/modules/GAMEMANAGER.md | 1 + 7 files changed, 221 insertions(+), 13 deletions(-) create mode 100644 docs/architecture/RPC_STATUS_REPAIR_REPORT.md diff --git a/Panel/modules/gamemanager/home_handling_functions.php b/Panel/modules/gamemanager/home_handling_functions.php index b509fe3e..141258b0 100644 --- a/Panel/modules/gamemanager/home_handling_functions.php +++ b/Panel/modules/gamemanager/home_handling_functions.php @@ -124,12 +124,11 @@ function gsp_agent_port_listening($remote, $server_port) if ($server_port <= 0 || !method_exists($remote, 'exec')) { return null; } - $port_arg = escapeshellarg((string)$server_port); - $command = 'p='.$port_arg.'; ' - . 'if command -v ss >/dev/null 2>&1; then ss -lntu 2>/dev/null; else netstat -an 2>/dev/null; fi ' + $port_pattern = '[:.]' . $server_port . '([[:space:]]|$)'; + $command = 'if command -v ss >/dev/null 2>&1; then ss -lntu 2>/dev/null; else netstat -an 2>/dev/null; fi ' . '| tr -d "\r" ' . '| grep -Eai "(LISTEN|LISTENING|UDP|tcp|udp)" ' - . '| grep -E "[:.]$p([[:space:]]|$)" >/dev/null ' + . '| grep -E ' . escapeshellarg($port_pattern) . ' >/dev/null ' . '&& echo GSP_PORT_LISTENING || echo GSP_PORT_CLOSED'; $output = $remote->exec($command); if (strpos((string)$output, 'GSP_PORT_LISTENING') !== false) { diff --git a/docs/agents/WINDOWS_AGENT.md b/docs/agents/WINDOWS_AGENT.md index 756e25cd..9ec9b35a 100644 --- a/docs/agents/WINDOWS_AGENT.md +++ b/docs/agents/WINDOWS_AGENT.md @@ -2,11 +2,11 @@ ## Role -`Agent-Windows/ogp_agent.pl` is the Windows/Cygwin execution agent for GSP. It mirrors the Linux agent as closely as practical, while using Windows-compatible paths, processes, and wrappers. +`Agent-Windows/OGP64/OGP/ogp_agent.pl` is the Windows/Cygwin execution agent currently tracked in this repository. It mirrors the Linux agent as closely as practical, while using Windows-compatible paths, processes, and wrappers. ## Important Files -- `Agent-Windows/ogp_agent.pl` +- `Agent-Windows/OGP64/OGP/ogp_agent.pl` - `Agent-Windows/php-query/` - `Agent-Windows/ArmaBE/` - `Agent-Windows/Cfg/` @@ -62,7 +62,7 @@ The Cygwin-side helper performs the shell work: 1. enter `/OGP` 2. normalize CRLF to LF for `.pl`, `.pm`, `.sh`, and `.cfg` files under `/OGP` 3. source `/OGP/Cfg/bash_prefs.cfg` -4. optionally update only `Agent-Windows/ogp_agent.pl` from Forgejo when `agent_auto_update=1` +4. optionally update only the Windows agent file from Forgejo when `agent_auto_update=1` 5. backup the current `/OGP/ogp_agent.pl` 6. validate the updated agent with `perl -c` 7. restore the backup if validation fails @@ -72,7 +72,7 @@ Default optional update source: - repo: `http://forge.runlevelsystems.com/dev/GSP.git` - branch: `Panel-unstable` -- source file: `Agent-Windows/ogp_agent.pl` +- source file: `Agent-Windows/OGP64/OGP/ogp_agent.pl` in the current repo layout - target file: `/OGP/ogp_agent.pl` Auto-update failure is non-fatal. Missing `git`, clone failure, missing source file, or failed validation should warn and continue with the current installed agent. diff --git a/docs/architecture/API_REFERENCE.md b/docs/architecture/API_REFERENCE.md index 68b01482..754c797f 100644 --- a/docs/architecture/API_REFERENCE.md +++ b/docs/architecture/API_REFERENCE.md @@ -49,7 +49,7 @@ Transport: - XML-RPC over HTTP - endpoint path `/RPC2` - wrapper `Panel/includes/lib_remote.php` -- server implementations in `Agent_Linux/ogp_agent.pl` and `Agent-Windows/ogp_agent.pl` +- server implementations in `Agent_Linux/ogp_agent.pl` and `Agent-Windows/OGP64/OGP/ogp_agent.pl` Primary categories: @@ -264,6 +264,13 @@ Rules: - agent process/session or game-port evidence is sufficient for online - `UNKNOWN` is reserved for unreachable or inconclusive agent state +Panel fallback behavior: + +- `Panel/modules/gamemanager/home_handling_functions.php` calls `remote_server_status()` first. +- If that structured RPC is unavailable or ambiguous, the Panel calls `is_screen_running()`. +- The Panel then calls generic agent `exec()` with an `ss`/`netstat` port probe for the configured game port. +- The fallback port grep must match normal listener output such as `:2302` or `.2302`; do not shell-quote the port inside the regex. + ## Scheduler-As-API Contract Agent cron jobs often execute URLs like: diff --git a/docs/architecture/PANEL_AGENT_COMMANDS.md b/docs/architecture/PANEL_AGENT_COMMANDS.md index fcb98716..a32422d6 100644 --- a/docs/architecture/PANEL_AGENT_COMMANDS.md +++ b/docs/architecture/PANEL_AGENT_COMMANDS.md @@ -8,7 +8,7 @@ Primary files: - `Panel/includes/lib_remote.php` - `Agent_Linux/ogp_agent.pl` -- `Agent-Windows/ogp_agent.pl` +- `Agent-Windows/OGP64/OGP/ogp_agent.pl` Transport: @@ -24,7 +24,7 @@ Linux dispatch table: Windows dispatch table: -- `Agent-Windows/ogp_agent.pl` +- `Agent-Windows/OGP64/OGP/ogp_agent.pl` Important parity note: @@ -210,5 +210,5 @@ Notable wrapper methods: Commands were confirmed from: - `rg -n "methods =>" Agent_Linux Agent-Windows` -- `rg -n "^sub .*without_decrypt|^sub component_update|^sub remote_query|^sub steam_workshop|^sub scheduler_" Agent_Linux/ogp_agent.pl Agent-Windows/ogp_agent.pl` +- `rg -n "^sub .*without_decrypt|^sub component_update|^sub remote_query|^sub steam_workshop|^sub scheduler_" Agent_Linux/ogp_agent.pl Agent-Windows/OGP64/OGP/ogp_agent.pl` - `rg -n "public function .*\\(" Panel/includes/lib_remote.php` diff --git a/docs/architecture/RPC_STATUS_REPAIR_REPORT.md b/docs/architecture/RPC_STATUS_REPAIR_REPORT.md new file mode 100644 index 00000000..bb4d28d7 --- /dev/null +++ b/docs/architecture/RPC_STATUS_REPAIR_REPORT.md @@ -0,0 +1,200 @@ +# RPC Status Repair Report + +## Purpose + +This report documents the investigation and repair for the Panel message: + +```text +Error occurred on the remote host. Agent status: UNKNOWN. Agent status RPC unavailable. +``` + +The scope of this pass was status/RPC communication only. Steam Workshop, updater, scheduler, and unrelated module behavior were intentionally left unchanged. + +## Root Cause + +The repository agents currently expose the structured `server_status` RPC on both Linux and Windows/Cygwin: + +- Linux: `Agent_Linux/ogp_agent.pl` +- Windows/Cygwin: `Agent-Windows/OGP64/OGP/ogp_agent.pl` + +The Panel also contains a fallback path for older or stale live agents where `server_status` is unavailable: + +1. call `remote_server_status()` / agent `server_status` +2. call `is_screen_running()` +3. call agent `exec()` with an `ss`/`netstat` port probe + +The fallback port probe was malformed. It shell-quoted the port before interpolating it into the grep regex. For port `2302`, the Panel generated a pattern equivalent to: + +```text +[:.]'2302'([[:space:]]|$) +``` + +Normal `ss` and `netstat` output contains `:2302` or `.2302`, not quotes around the port. Therefore the port fallback never matched listening game ports. If the live agent was stale, unreachable for `server_status`, or unable to report the screen session, the Panel had no working fallback and displayed `UNKNOWN`. + +The fix builds the numeric listener regex directly and shell-quotes only the complete grep pattern: + +```text +[:.]2302([[:space:]]|$) +``` + +## Status Flow + +| Step | File / Function | RPC / Handler | Purpose | Expected result | +|---|---|---|---|---| +| 1 | `Panel/modules/gamemanager/server_monitor.php` | `get_agent_server_status()` | Game Monitor asks for current state | structured status array | +| 2 | `Panel/modules/gamemanager/start_server.php` | `get_agent_server_status(..., "STARTING")` | Show post-start state | `STARTING` or `ONLINE` | +| 3 | `Panel/modules/gamemanager/stop_server.php` | `get_agent_server_status(..., "STOPPING")` | Verify stop result | `STOPPING`, `OFFLINE`, or `ONLINE` if stop failed | +| 4 | `Panel/modules/gamemanager/restart_server.php` | `get_agent_server_status()` | Verify restart state | active state or offline | +| 5 | `Panel/modules/gamemanager/home_handling_functions.php` | `remote_server_status()` | Primary structured status check | agent `server_status` hash | +| 6 | `Panel/modules/gamemanager/home_handling_functions.php` | `is_screen_running()` | Fallback managed session check | `1`, `0`, or inconclusive | +| 7 | `Panel/modules/gamemanager/home_handling_functions.php` | `exec()` | Fallback agent-side game port probe | `GSP_PORT_LISTENING` or `GSP_PORT_CLOSED` | + +## Status Decision Rules + +| Evidence | Panel status | +|---|---| +| Agent unreachable or no reliable check can be completed | `UNKNOWN` | +| Agent says process/session exists | `ONLINE` | +| Agent says configured game port is listening | `ONLINE` | +| Fallback `is_screen_running` returns true | `ONLINE` | +| Fallback `exec` port probe returns `GSP_PORT_LISTENING` | `ONLINE` | +| Agent/fallbacks confirm no session and no listening port | `OFFLINE` | +| Game query fails but session/process/port is known | `ONLINE` with query metadata unavailable | + +LGSL/GameQ/Steam query success is not a base online/offline signal. It is optional metadata. + +## Panel RPC Wrappers + +Source: `Panel/includes/lib_remote.php`. + +| Panel wrapper | Agent RPC | +|---|---| +| `rfile_exists()` | `rfile_exists` | +| `status_chk()` | `quick_chk` | +| `get_log()` | `get_log` | +| `remote_stop_server()` | `stop_server` | +| `remote_send_rcon_command()` | `send_rcon_command` | +| `remote_readfile()` | `readfile` | +| `remote_writefile()` | `writefile` | +| `remote_rebootnow()` | `rebootnow` | +| `steam()` | `steam` | +| `steam_cmd()` | `steam_cmd` | +| `fetch_steam_version()` | `fetch_steam_version` | +| `installed_steam_version()` | `installed_steam_version` | +| `automatic_steam_update()` | `automatic_steam_update` | +| `masterServerUpdate()` | `master_server_update` | +| `game_update_active()` | `game_update_active` | +| `start_file_download()` | `start_file_download` | +| `is_file_download_in_progress()` | `is_file_download_in_progress` | +| `uncompress_file()` | `uncompress_file` | +| `remote_dirlist()` | `dirlist` | +| `remote_dirlistfm()` | `dirlistfm` | +| `cpu_count()` | `cpu_count` | +| `renice_process()` | `renice_process` | +| `universal_start()` | `universal_start` | +| `lock_additional_home_files()` | `lock_additional_files` | +| `what_os()` | `what_os` | +| `discover_ips()` | `discover_ips` | +| `is_screen_running()` | `is_screen_running` | +| `remote_server_status()` | `server_status` | +| `mon_stats()` | `mon_stats` | +| `clone_home()` | `clone_home` | +| `remove_home()` | `remove_home` | +| `remote_restart_server()` | `restart_server` | +| `sudo_exec()` | `sudo_exec` | +| `exec()` | `exec` | +| `secure_path()` | `secure_path` | +| `get_chattr()` | `get_chattr` | +| `ftp_mgr()` | `ftp_mgr` | +| `compress_files()` | `compress_files` | +| `stop_fastdl()` | `stop_fastdl` | +| `start_fastdl()` | `start_fastdl` | +| `restart_fastdl()` | `restart_fastdl` | +| `fastdl_status()` | `fastdl_status` | +| `fastdl_get_aliases()` | `fastdl_get_aliases` | +| `fastdl_add_alias()` | `fastdl_add_alias` | +| `fastdl_del_alias()` | `fastdl_del_alias` | +| `fastdl_get_info()` | `fastdl_get_info` | +| `fastdl_create_config()` | `fastdl_create_config` | +| `agent_restart()` | `agent_restart` | +| `component_update()` | `component_update` | +| `scheduler_list_tasks()` | `scheduler_list_tasks` | +| `scheduler_del_task()` | `scheduler_del_task` | +| `scheduler_add_task()` | `scheduler_add_task` | +| `scheduler_edit_task()` | `scheduler_edit_task` | +| `remote_get_file_part()` | `get_file_part` | +| `shell_action()` | `shell_action` | +| `stop_update()` | `stop_update` | +| `remote_query()` | `remote_query` | +| `send_steam_guard_code()` | `send_steam_guard_code` | +| `steam_workshop()` | `steam_workshop` | +| `get_workshop_mods_info()` | `get_workshop_mods_info` | + +## Agent RPC Methods + +Linux and Windows/Cygwin expose the same current status-critical methods: + +| Agent RPC | Linux | Windows/Cygwin | Notes | +|---|---|---|---| +| `quick_chk` | Yes | Yes | Agent reachability / key check | +| `server_status` | Yes | Yes | Structured status hash | +| `is_screen_running` | Yes | Yes | Managed screen/session fallback | +| `exec` | Yes | Yes | Generic command execution, used for port fallback | +| `universal_start` | Yes | Yes | Start server | +| `stop_server` | Yes | Yes | Stop server | +| `restart_server` | Yes | Yes | Restart server | +| `get_log` | Yes | Yes | Log retrieval | + +Linux also exposes `renice_process` and `lock_additional_files`, which are absent from Windows/Cygwin. Those are not involved in this status regression. + +## Mismatches Found + +| Mismatch | Impact | +|---|---| +| Documentation referenced `Agent-Windows/ogp_agent.pl`, but the current tracked file is `Agent-Windows/OGP64/OGP/ogp_agent.pl`. | Confuses future debugging and validation. Documentation was updated. | +| Panel fallback port regex inserted a shell-quoted port into a grep regex. | Prevented `ss`/`netstat` fallback from detecting running servers after `server_status` RPC was unavailable. Fixed. | +| Some non-status wrappers in `lib_remote.php` reference legacy RPC names whose current support should be checked before future work, such as `steam` and `game_update_active`. | Out of scope for this status repair. | + +## Files Changed + +- `Panel/modules/gamemanager/home_handling_functions.php` +- `docs/features/STATUS_SYSTEM.md` +- `docs/modules/GAMEMANAGER.md` +- `docs/architecture/API_REFERENCE.md` +- `docs/architecture/PANEL_AGENT_COMMANDS.md` +- `docs/agents/WINDOWS_AGENT.md` +- `docs/architecture/RPC_STATUS_REPAIR_REPORT.md` + +## Validation Commands + +Run from repository root: + +```bash +php -l Panel/modules/gamemanager/home_handling_functions.php +perl -c Agent_Linux/ogp_agent.pl +perl -c Agent-Windows/OGP64/OGP/ogp_agent.pl +rg -n "p=\\$port_arg|\\[:\\.\\]\\$p|Agent-Windows/ogp_agent\\.pl" \ + Panel/modules/gamemanager/home_handling_functions.php \ + docs/features/STATUS_SYSTEM.md \ + docs/modules/GAMEMANAGER.md \ + docs/architecture/API_REFERENCE.md \ + docs/architecture/PANEL_AGENT_COMMANDS.md \ + docs/agents/WINDOWS_AGENT.md +``` + +Live validation still requires a configured remote host: + +1. Start or identify a known running server. +2. Confirm the game port is listening on the agent host with `ss -lntu` or `netstat -an`. +3. Open Game Monitor. +4. Confirm the server displays green `ONLINE` when either the screen/session or port is detected. +5. Stop the server. +6. Confirm the server displays `OFFLINE` only after session/process and port are gone. + +## Recommended Automated Tests + +- Unit test `gsp_agent_port_listening()` command generation for port `2302`; it must produce a grep pattern matching `:2302` and not `:'2302'`. +- Mock `remote_server_status()` returning `UNKNOWN` and mock `exec()` returning `GSP_PORT_LISTENING`; `get_agent_server_status()` must return `ONLINE`. +- Mock `remote_server_status()` unavailable, `is_screen_running()` returning `1`; `get_agent_server_status()` must return `ONLINE`. +- Mock all fallbacks returning closed/false; `get_agent_server_status()` may return `OFFLINE`. +- Integration smoke test against Linux and Windows/Cygwin agents for `quick_chk`, `server_status`, `is_screen_running`, and `exec`. diff --git a/docs/features/STATUS_SYSTEM.md b/docs/features/STATUS_SYSTEM.md index c06306db..07304aff 100644 --- a/docs/features/STATUS_SYSTEM.md +++ b/docs/features/STATUS_SYSTEM.md @@ -14,7 +14,7 @@ Important files: - `Panel/modules/gamemanager/home_handling_functions.php` - `Panel/modules/gamemanager/server_monitor.php` - `Agent_Linux/ogp_agent.pl` -- `Agent-Windows/ogp_agent.pl` +- `Agent-Windows/OGP64/OGP/ogp_agent.pl` ## Panel Display Behavior @@ -43,6 +43,7 @@ The port fallback is deliberately cross-platform: - Linux normally uses `ss -lntu`, then `netstat`. - Cygwin/Windows normally uses `netstat -an`. - The Panel-side fallback parses complete command output instead of assuming the listening address is always in the same column. +- The port fallback must build a literal numeric grep pattern such as `[:.]2302([[:space:]]|$)`. A previous regression shell-quoted the port before interpolating it into the regex, producing a pattern like `[:.]'2302'...` that could never match normal `ss`/`netstat` output. Agent behavior now treats a listening game port as `ONLINE` even if the managed screen/session cannot be found. The UI may still show the warning from `last_error`, but it must not show a false red/offline or gray/unknown state when the game port proves the server is running. diff --git a/docs/modules/GAMEMANAGER.md b/docs/modules/GAMEMANAGER.md index f1bcb5d1..64529b5e 100644 --- a/docs/modules/GAMEMANAGER.md +++ b/docs/modules/GAMEMANAGER.md @@ -77,6 +77,7 @@ Repair note: - `Panel/modules/gamemanager/home_handling_functions.php` contains the status fallback. - The port fallback intentionally parses full `ss`/`netstat` output instead of relying on one fixed field, because Cygwin and Linux output differ. +- The port fallback sends a generated command through the existing agent `exec` RPC. The grep expression must contain the numeric port directly, for example `[:.]2302([[:space:]]|$)`, not a shell-quoted value. If the regex contains quotes around the port, running servers can remain `UNKNOWN` after `server_status` is unavailable. - The Windows and Linux agents report `ONLINE` when the configured game port is listening even if the managed screen/session is missing, with a warning in `last_error`. ## Game Monitor Display Rules