mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-10-12 02:22:26 +00:00
* feat(acl): add AclHandle to swap ACL rules atomically at runtime AccessControl is immutable after loading, and ServiceContext used to store it directly, so rules were frozen for the lifetime of the process. Wrap the active rules in an ArcSwap-based AclHandle. Readers take a cheap Arc snapshot which stays valid across a swap, enabling hot-reloading without interrupting the service. reload() re-parses the retained file path and only swaps the new rules in when parsing succeeds. * feat(local): hot-reload the global ACL file through ServiceContext Store the ACL as an AclHandle in ServiceContext. set_acl keeps its signature and wraps the rules in a handle; cloned contexts share it, so every listener sees the same swappable rules. acl() now returns an Arc<AccessControl> snapshot instead of a reference, which cannot be preserved across an atomic swap. ServiceContext::reload_acl() re-reads the ACL file, swaps the new rules in atomically and clears the DNS relay's reverse-lookup cache, which caches decisions derived from the old rules. On failure the previous rules stay active. Server keeps the global context and exposes acl_reload_context() so embedders can trigger reloads. Contexts with a private ACL keep their own handle and are not covered by the global reload. * feat(local): reload the ACL file on SIGUSR2 in sslocal sslocal already reloads its server list from the config file on SIGUSR1. Add a second reload trigger on SIGUSR2 for the ACL file, so routing rules can be updated without restarting the process or interrupting established connections. Like the SIGUSR1 reloader, the task is Unix-only and compiles away on Windows. ssservice's local mode shares this module and inherits it. Document both signals in the README and cover the reload with an integration test that verifies new connections are routed by the new rules after each reload. * refactor(acl): address review feedback for ACL hot-reload - Rename `AclHandle` to `AccessControlHandle`, aligning the name with `AccessControl` - Rename `Server::acl_reload_context` to `Server::context`, so the shared global context can be reused for other runtime operations - Fold reload logging into `AccessControlHandle::reload`, keeping `ServiceContext::reload_acl` thin - Record the config file and the ACL file as absolute paths at load time, so both SIGUSR1 and SIGUSR2 reloads keep working after daemonizing (which `chdir`s to `/`); symlinks are deliberately preserved by resolving with cwd instead of canonicalizing * refactor(local): drop needless pending() in the non-Unix ACL reload task stub The task may complete immediately: the main loop already tolerates early task exit, mirroring the existing Windows behavior of the SIGUSR1 reload task. This also releases the ServiceContext clone right away instead of holding it forever. --------- Co-authored-by: ty <[email protected]>