How Shadowsocks-Windows Handles System Power Suspend/Resume

Shadowsocks-Windows registers a SystemEvents.PowerModeChanged handler in Program.cs that calls MainController.Stop() on suspend and MainController.Start(true) on resume, waiting 10 seconds after wake-up to allow network adapters to re-initialize before restarting the proxy services.

The shadowsocks/shadowsocks-windows client must gracefully handle Windows sleep cycles to prevent network leaks and ensure seamless reconnection. The application hooks into the operating system's power management events to coordinate the shutdown and recovery of its core ShadowsocksController.

How Power State Changes Are Detected

The application subscribes to Microsoft.Win32.SystemEvents.PowerModeChanged during initialization in Program.cs. This Windows Forms event provides real-time notifications whenever the OS enters or exits a low-power state.

// Registration in Program.cs (lines 110-119)
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;

The handler SystemEvents_PowerModeChanged inspects the PowerModeChangedEventArgs.Mode property to determine whether the system is suspending or resuming.

Suspend Handling: Graceful Shutdown

When PowerModes.Suspend is detected, the application immediately shuts down all active networking components to ensure the OS can safely enter sleep mode without holding open sockets or proxy connections.

The MainController.Stop() method performs the following actions:

  • Closes the local SOCKS5 listener
  • Shuts down the PAC daemon and PAC server
  • Releases all active proxy processes and sockets
  • Logs "controller stopped" and "os suspend" for diagnostics

This cleanup is critical because Windows may freeze or terminate applications that hold network resources during sleep transitions.

Key Code Path for Suspend

In Program.cs (lines 110-117 and 210-217), the suspend branch executes:

case PowerModes.Suspend:
    // cleanly stop everything before the OS sleeps
    MainController.Stop();
    break;

Resume Handling: Controller Recovery

On PowerModes.Resume, the application does not immediately restart. Instead, it spawns a background task that waits 10 seconds before invoking MainController.Start(true). This delay allows Windows to re-initialize network adapters and restore connectivity.

case PowerModes.Resume:
    // give the OS a moment, then restart the controller
    Task.Factory.StartNew(() =>
    {
        Thread.Sleep(10_000);
        MainController.Start(true);
    });
    break;

The systemWakeUp Flag

The ShadowsocksController.Start(bool systemWakeUp) method (implemented in ShadowsocksController.cs, lines 14-30) uses the boolean parameter to distinguish between a cold start and a wake-from-suspend recovery:

  • Configuration reload: Reload() refreshes settings and restarts the listener and PAC services
  • System proxy re-application: The controller reapplies the system proxy settings to restore traffic redirection
  • Skip first-run logic: When systemWakeUp is true, the method skips version-upgrade checks (_config.firstRunOnNewVersion), allowing immediate recovery
public void Start(bool systemWakeUp = false)
{
    // skip first‑run upgrade when waking from suspend
    if (_config.firstRunOnNewVersion && !systemWakeUp) { /* upgrade logic */ }

    Reload();               // re‑load config, listeners, PAC, etc.
    if (!systemWakeUp)      // normal launch: register hotkeys
        HotkeyReg.RegAllHotkeys();
}

Key Implementation Details

Component File Path Role in Power Management
Power Event Registration shadowsocks-csharp/Program.cs (lines 110-119) Subscribes to SystemEvents.PowerModeChanged
Suspend Logic shadowsocks-csharp/Program.cs (lines 110-117) Calls MainController.Stop() to release resources
Resume Logic shadowsocks-csharp/Program.cs (lines 188-202) Delays 10s then calls MainController.Start(true)
Controller Start Controller/ShadowsocksController.cs (lines 14-30) Implements Start(bool systemWakeUp) with wake-up detection
Controller Stop Controller/ShadowsocksController.cs Implements Stop() to close listeners and PAC daemon
PAC Services Controller/Service/PACDaemon.cs / PACServer.cs Restarted by controller during resume recovery

Summary

  • Shadowsocks-Windows hooks SystemEvents.PowerModeChanged in Program.cs to monitor power state transitions.
  • During suspend, MainController.Stop() cleanly terminates the proxy listener, PAC daemon, and network sockets to prepare for sleep.
  • During resume, a background task waits 10 seconds for network adapter initialization, then calls MainController.Start(true).
  • The systemWakeUp flag in ShadowsocksController.Start() skips first-run upgrade checks and triggers rapid recovery of proxy services and system proxy settings.

Frequently Asked Questions

Why does Shadowsocks-Windows wait 10 seconds after resume?

The 10-second delay in Program.cs (lines 188-202) allows Windows to complete network adapter re-initialization and restore connectivity. Starting the proxy controller too early results in binding failures or unreachable remote servers because the network stack is not yet fully operational during the early seconds of wake-up.

What components are stopped during system suspend?

According to the source code in ShadowsocksController.Stop(), the application shuts down the local SOCKS5 listener, the PAC daemon, the PAC server, and any active proxy processes. This releases all sockets and allows the OS to enter low-power states safely without hanging on open network connections.

What is the purpose of the systemWakeUp flag in Start()?

The systemWakeUp parameter in ShadowsocksController.Start(bool systemWakeUp) signals that the application is recovering from suspend rather than launching fresh. When true, the method skips version-upgrade prompts and first-run configuration dialogs, immediately reloading settings and restarting services to minimize downtime.

Where is the power event handler registered?

The handler is registered in shadowsocks-csharp/Program.cs at lines 110-119 using SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;. This single subscription captures both suspend and resume events, routing them to the appropriate controller methods based on the PowerModes enum value.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →