process_windows.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. //go:build windows
  2. package xray
  3. import (
  4. "os/exec"
  5. "sync"
  6. "unsafe"
  7. "github.com/mhsanaei/3x-ui/v3/logger"
  8. "golang.org/x/sys/windows"
  9. )
  10. var (
  11. killOnExitJobOnce sync.Once
  12. killOnExitJob windows.Handle
  13. killOnExitJobErr error
  14. )
  15. func ensureKillOnExitJob() (windows.Handle, error) {
  16. killOnExitJobOnce.Do(func() {
  17. h, err := windows.CreateJobObject(nil, nil)
  18. if err != nil {
  19. killOnExitJobErr = err
  20. return
  21. }
  22. info := windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION{
  23. BasicLimitInformation: windows.JOBOBJECT_BASIC_LIMIT_INFORMATION{
  24. LimitFlags: windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
  25. },
  26. }
  27. _, err = windows.SetInformationJobObject(
  28. h,
  29. windows.JobObjectExtendedLimitInformation,
  30. uintptr(unsafe.Pointer(&info)),
  31. uint32(unsafe.Sizeof(info)),
  32. )
  33. if err != nil {
  34. windows.CloseHandle(h)
  35. killOnExitJobErr = err
  36. return
  37. }
  38. killOnExitJob = h
  39. })
  40. return killOnExitJob, killOnExitJobErr
  41. }
  42. func attachChildLifetime(cmd *exec.Cmd) {
  43. if cmd == nil || cmd.Process == nil {
  44. return
  45. }
  46. job, err := ensureKillOnExitJob()
  47. if err != nil {
  48. logger.Warning("xray: kill-on-exit job unavailable:", err)
  49. return
  50. }
  51. h, err := windows.OpenProcess(windows.PROCESS_SET_QUOTA|windows.PROCESS_TERMINATE, false, uint32(cmd.Process.Pid))
  52. if err != nil {
  53. logger.Warning("xray: OpenProcess for job attach failed:", err)
  54. return
  55. }
  56. defer windows.CloseHandle(h)
  57. if err := windows.AssignProcessToJobObject(job, h); err != nil {
  58. logger.Warning("xray: AssignProcessToJobObject failed:", err)
  59. }
  60. }