Replace the embedded UI with a file manager: sidebar, details table, keyboard shortcuts, uploads, copy/move and extraction. Games, System, Transfers and Settings use the same components. The previous UI is archived in web/legacy/ and left out of the embedded resources. The restyle is flat: donation banner, credits with the maintainer photo, and no gradients or card shadows. JavaScript stays ES5.
4.4 KiB
Rest Mode Resilience
zftpd survives PlayStation Rest Mode cycles by recreating dead listen sockets and exposing a stable process identity so clients can reconnect cleanly.
There is no “enter rest mode” protocol command — Rest Mode is an environmental event (sockets die / network stack drops / payload may be re-injected).
Does activity resume after wake?
Yes, if the payload process survives Rest Mode (typical on PS4/PS5 when the process is only suspended):
- Existing FTP/HTTP TCP sessions die (the stack drops them)
- zftpd detects the dead listen socket (
EBADF/ENOTSOCK/ liveness probe) - It recreates
bind/listenwith exponential backoff while the network is down - On success it shows an on-screen notification (
Server resumed/HTTP resumed) - New client connections work again; FTP clients and ZHTTP reconnect
No automatic resume if the payload was terminated during Rest Mode — you must
re-inject zftpd. Clients then see a new instance_id.
Scenarios
| Case | Payload process | Listen sockets | zftpd behaviour |
|---|---|---|---|
| Terminated | Dies | Gone | Requires re-inject; new instance_id |
| Suspended | Survives | Invalid (EBADF / ENOTSOCK) |
Recreate listener with backoff |
| Suspended + stale FD | Survives | FD looks open, stack down | Liveness probe → recreate |
Server (FTP)
pal_resilient_accept() (src/platform/pal_resilient_server.c):
- Detects listener loss on
accept()(EBADF,ENOTSOCK,EINVAL) - Periodically probes the listen FD (
getsockopt(SO_TYPE)/SO_ACCEPTCONN) - Recreates
socket→SO_REUSEADDR→bind→listenwith backoff:500 → 1000 → 2000 → 4000 → 8000 → 10000 ms(indefinite while running) - Every few failed attempts calls
pal_network_reinit() - Sends an on-screen notification:
zftpd: Server resumed on <ip>:<port>
Existing FTP control/data connections are not preserved (TCP is dead).
Clients reconnect; file resume remains FTP REST + STOR/RETR.
Server (HTTP / ZHTTP)
http_server.c mirrors the same model on the event-loop listener:
EVENT_ERROR/EVENT_CLOSEor lost-errno onaccept()schedules recreate- A detached thread retries with the same backoff
- A wake pipe hands the new FD back to the event-loop thread for
event_loop_add(handler table is not thread-safe) - Notification:
zftpd: HTTP resumed on port <n>
Daemon identity
Process-lifetime values from ftp_instance.c:
| Field | Meaning |
|---|---|
daemon_instance_id |
Random uint64, stable until process exit |
daemon_start_monotonic_ns |
CLOCK_MONOTONIC at first generation |
Exposed to clients via:
- HTTP
GET /api/status→ JSONinstance_id,start_monotonic_ns,version,pid - FTP
FEATlineXZFTPD INSTANCE <hex> - FTP
STATreply includes the instance hex
instance_id vs previous |
Meaning | Client action |
|---|---|---|
| Same | Payload survived | Keep UI state, refresh listings |
| Different | Re-injected / new process | Treat remote handles as invalid |
| Missing / zero (legacy) | Old build | Skip rotation check |
ZHTTP client reconnect
web/js/api.js (connection monitor) and web/js/app.js (status UI):
- Health poll of
/api/statusevery 5s - Two consecutive transport failures → offline banner in the UI
- Exponential backoff probe (0.5s → 10s) until
/api/statussucceeds api.ready()gates POST/upload while offline or reconnecting- Toast on reconnect; a changed
instance_idis reported as a daemon restart
What is preserved vs invalidated
Preserved (same process): daemon heap, session pool slots free for new clients,
instance_id, filesystem, config.
Invalidated always: live TCP sessions, PASV ports, in-flight transfers.
Client-side preserved across ZHTTP reconnect: current path, UI view, theme. Listings are refreshed on reconnect.
Tests
make test
# includes tests/test_instance.c — identity stability + backoff helpers
Hardware validation (recommended)
- Start zftpd on PS5, connect FTP + open ZHTTP
- Enter Rest Mode → wait → wake
- Confirm notification “Server resumed” / “HTTP resumed”
- FTP client reconnects; ZHTTP shows “Connection restored”
GET /api/statusreturns the sameinstance_idif the payload survived- Kill/re-inject payload →
instance_idchanges; ZHTTP reports daemon restart