mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-27 12:30:13 +03:00
The run() cleanup block was guarded by `except (ConnectionError, OSError):`, so exits via asyncio.CancelledError or any other exception type skipped cleanup. Result: `_reader_process` stays pinned to the dead reader and `_get_reader()` returns None for every subsequent client — the silent-proxy symptom described in #2344. Convert the except block to try/finally so cleanup always runs, regardless of how `_process()` exits. Also: - catch asyncio.CancelledError + generic Exception (with log.exception) so unexpected failures don't swallow the cleanup - reset `_current_read = None` after cancellation - use `dict.pop(..., None)` instead of `del` to avoid KeyError races if the broadcast loop's timeout handler already removed the entry Triggering pattern observed in practice: a diagnostic tool opens a console, sends a few commands, and closes abruptly (e.g. from a test harness or orchestration script that cancels its Task). If the `_process()` task was awaiting on one of the `network_read` / `reader_read` futures at the time of cancellation, the CancelledError propagates up through `run()` and bypasses the ConnectionError-only except clause. The proxy accepts future connections (the listen socket is still alive) but never forwards any data because `_reader_process` never got reset. Validated against gns3/gns3-server:latest (2.2.56.1) running a 10-scenario sequential regression batch that previously hung reliably on the 4th sp_v1 / L3VPN scenario and now completes cleanly across all 10.