фикс краша при отключении vpn (vibe-kanban 4dcd8b1b)

У нас реализовано подключение к vpn и оно отлично работает. Но при нажатии на кнопку отключить происходит краш:
PS C:\\Users\\hamy\\HamyDev\\HamyVPNClient\\HamyVPNClient> go run .

2026/01/16 20:01:32 Sing-box configuration written to config.json

Exception 0xc0000005 0x1 0x1 0x7ffbb351b5d5

PC=0x7ffbb351b5d5

signal arrived during external code execution
This commit is contained in:
Vibe Kanban
2026-01-16 20:12:04 +03:00
parent 1f54670e3e
commit a0d76586a9
3 changed files with 54 additions and 24 deletions

6
configs.json Normal file
View File

@@ -0,0 +1,6 @@
[
{
"Title": "Конфиг 1",
"URL": "vless://3da694cb-cca3-4849-81c3-9ff60c4dc399@193.124.93.179:39590?type=tcp\u0026encryption=none\u0026security=none#TCP%20HamyVPN-TEST2"
}
]

Binary file not shown.

72
main.go
View File

@@ -174,7 +174,10 @@ func runSingBox(configPath string) error {
if currentProcess != nil && currentProcess.Process != nil { if currentProcess != nil && currentProcess.Process != nil {
// Attempt to terminate gracefully first // Attempt to terminate gracefully first
currentProcess.Process.Kill() currentProcess.Process.Kill()
currentProcess.Wait() // Wait for graceful termination // Wait for the process to finish in a separate goroutine to avoid blocking
go func(p *exec.Cmd) {
p.Wait() // Wait for graceful termination
}(currentProcess)
currentProcess = nil currentProcess = nil
} }
@@ -213,6 +216,7 @@ func isProcessRunning(cmd *exec.Cmd) bool {
} }
// On Windows, check if the process is still alive by getting its state // On Windows, check if the process is still alive by getting its state
// Using syscall.Signal(0) just checks if we can send a signal (process exists)
err := cmd.Process.Signal(syscall.Signal(0)) err := cmd.Process.Signal(syscall.Signal(0))
return err == nil return err == nil
} }
@@ -220,17 +224,27 @@ func isProcessRunning(cmd *exec.Cmd) bool {
// killCurrentProcess terminates the current sing-box process if running // killCurrentProcess terminates the current sing-box process if running
func killCurrentProcess() { func killCurrentProcess() {
processMutex.Lock() processMutex.Lock()
defer processMutex.Unlock()
if currentProcess != nil && currentProcess.Process != nil { // Create a local copy of the current process to avoid race conditions
cmd := currentProcess
currentProcess = nil
processMutex.Unlock()
if cmd != nil && cmd.Process != nil {
// Check if the process is still running before attempting to kill it // Check if the process is still running before attempting to kill it
if isProcessRunning(currentProcess) { if isProcessRunning(cmd) {
// Use TerminateProcess syscall for more reliable termination on Windows // Use TerminateProcess syscall for more reliable termination on Windows
currentProcess.Process.Kill() err := cmd.Process.Kill()
// Wait for the process to actually terminate if err != nil {
currentProcess.Wait() log.Printf("Error killing process: %v", err)
}
// Wait for the process to actually terminate in a separate goroutine to avoid blocking
go func(p *exec.Cmd) {
p.Wait() // Wait for the process to finish
}(cmd)
} }
currentProcess = nil
} }
} }
@@ -562,24 +576,34 @@ func disableSystemProxy() error {
func notifyProxyChange() { func notifyProxyChange() {
// Use Windows API to notify about proxy change // Use Windows API to notify about proxy change
// Call InternetSetOption to refresh proxy settings // Call InternetSetOption to refresh proxy settings
procInternetSetOption := syscall.NewLazyDLL("wininet.dll").NewProc("InternetSetOptionW") wininetDLL := syscall.NewLazyDLL("wininet.dll")
procInternetSetOption.Call( if wininetDLL != nil {
0, // hInternet = NULL procInternetSetOption := wininetDLL.NewProc("InternetSetOptionW")
39, // INTERNET_OPTION_SETTINGS_CHANGED if procInternetSetOption != nil {
0, // lpBuffer = NULL procInternetSetOption.Call(
0, // dwBufferLength = 0 0, // hInternet = NULL
) 39, // INTERNET_OPTION_SETTINGS_CHANGED
0, // lpBuffer = NULL
0, // dwBufferLength = 0
)
}
}
// Also send WM_SETTINGCHANGE to broadcast the change // Also send WM_SETTINGCHANGE to broadcast the change
procSendMessageTimeout := syscall.NewLazyDLL("user32.dll").NewProc("SendMessageTimeoutW") user32DLL := syscall.NewLazyDLL("user32.dll")
procSendMessageTimeout.Call( if user32DLL != nil {
0xFFFF, // HWND_BROADCAST procSendMessageTimeout := user32DLL.NewProc("SendMessageTimeoutW")
0x001A, // WM_SETTINGCHANGE if procSendMessageTimeout != nil {
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Proxy"))), procSendMessageTimeout.Call(
0, 0xFFFF, // HWND_BROADCAST
0x0002, // SMTO_ABORTIFHUNG 0x001A, // WM_SETTINGCHANGE
5000, // timeout uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Proxy"))),
) 0,
0x0002, // SMTO_ABORTIFHUNG
5000, // timeout
)
}
}
} }
func main() { func main() {