service_windows.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // Copyright 2015 Daniel Theophanes.
  2. // Use of this source code is governed by a zlib-style
  3. // license that can be found in the LICENSE file.
  4. package service
  5. import (
  6. "fmt"
  7. "os"
  8. "os/signal"
  9. "strconv"
  10. "sync"
  11. "time"
  12. "unsafe"
  13. "golang.org/x/sys/windows"
  14. "golang.org/x/sys/windows/registry"
  15. "golang.org/x/sys/windows/svc"
  16. "golang.org/x/sys/windows/svc/eventlog"
  17. "golang.org/x/sys/windows/svc/mgr"
  18. )
  19. const version = "windows-service"
  20. //penggy add for config restart on crash
  21. const (
  22. SC_ACTION_NONE = 0
  23. SC_ACTION_RESTART = 1
  24. SC_ACTION_REBOOT = 2
  25. SC_ACTION_RUN_COMMAND = 3
  26. SERVICE_CONFIG_FAILURE_ACTIONS = 2
  27. )
  28. type SERVICE_FAILURE_ACTIONS struct {
  29. ResetPeriod uint32
  30. RebootMsg *uint16
  31. Command *uint16
  32. ActionsCount uint32
  33. Actions uintptr
  34. }
  35. type SC_ACTION struct {
  36. Type uint32
  37. Delay uint32
  38. }
  39. func setServiceFailureActions(handle windows.Handle) error {
  40. t := []SC_ACTION{
  41. {Type: SC_ACTION_RESTART, Delay: uint32(1000)},
  42. {Type: SC_ACTION_RESTART, Delay: uint32(10000)},
  43. {Type: SC_ACTION_RESTART, Delay: uint32(60000)},
  44. }
  45. m := SERVICE_FAILURE_ACTIONS{ResetPeriod: uint32(60), ActionsCount: uint32(3), Actions: uintptr(unsafe.Pointer(&t[0]))}
  46. return windows.ChangeServiceConfig2(handle, SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&m)))
  47. }
  48. //-- penggy add for config restart on crash
  49. type windowsService struct {
  50. i Interface
  51. *Config
  52. errSync sync.Mutex
  53. stopStartErr error
  54. }
  55. // WindowsLogger allows using windows specific logging methods.
  56. type WindowsLogger struct {
  57. ev *eventlog.Log
  58. errs chan<- error
  59. }
  60. type windowsSystem struct{}
  61. func (windowsSystem) String() string {
  62. return version
  63. }
  64. func (windowsSystem) Detect() bool {
  65. return true
  66. }
  67. func (windowsSystem) Interactive() bool {
  68. return interactive
  69. }
  70. func (windowsSystem) New(i Interface, c *Config) (Service, error) {
  71. ws := &windowsService{
  72. i: i,
  73. Config: c,
  74. }
  75. return ws, nil
  76. }
  77. func init() {
  78. ChooseSystem(windowsSystem{})
  79. }
  80. func (l WindowsLogger) send(err error) error {
  81. if err == nil {
  82. return nil
  83. }
  84. if l.errs != nil {
  85. l.errs <- err
  86. }
  87. return err
  88. }
  89. // Error logs an error message.
  90. func (l WindowsLogger) Error(v ...interface{}) error {
  91. return l.send(l.ev.Error(3, fmt.Sprint(v...)))
  92. }
  93. // Warning logs an warning message.
  94. func (l WindowsLogger) Warning(v ...interface{}) error {
  95. return l.send(l.ev.Warning(2, fmt.Sprint(v...)))
  96. }
  97. // Info logs an info message.
  98. func (l WindowsLogger) Info(v ...interface{}) error {
  99. return l.send(l.ev.Info(1, fmt.Sprint(v...)))
  100. }
  101. // Errorf logs an error message.
  102. func (l WindowsLogger) Errorf(format string, a ...interface{}) error {
  103. return l.send(l.ev.Error(3, fmt.Sprintf(format, a...)))
  104. }
  105. // Warningf logs an warning message.
  106. func (l WindowsLogger) Warningf(format string, a ...interface{}) error {
  107. return l.send(l.ev.Warning(2, fmt.Sprintf(format, a...)))
  108. }
  109. // Infof logs an info message.
  110. func (l WindowsLogger) Infof(format string, a ...interface{}) error {
  111. return l.send(l.ev.Info(1, fmt.Sprintf(format, a...)))
  112. }
  113. // NError logs an error message and an event ID.
  114. func (l WindowsLogger) NError(eventID uint32, v ...interface{}) error {
  115. return l.send(l.ev.Error(eventID, fmt.Sprint(v...)))
  116. }
  117. // NWarning logs an warning message and an event ID.
  118. func (l WindowsLogger) NWarning(eventID uint32, v ...interface{}) error {
  119. return l.send(l.ev.Warning(eventID, fmt.Sprint(v...)))
  120. }
  121. // NInfo logs an info message and an event ID.
  122. func (l WindowsLogger) NInfo(eventID uint32, v ...interface{}) error {
  123. return l.send(l.ev.Info(eventID, fmt.Sprint(v...)))
  124. }
  125. // NErrorf logs an error message and an event ID.
  126. func (l WindowsLogger) NErrorf(eventID uint32, format string, a ...interface{}) error {
  127. return l.send(l.ev.Error(eventID, fmt.Sprintf(format, a...)))
  128. }
  129. // NWarningf logs an warning message and an event ID.
  130. func (l WindowsLogger) NWarningf(eventID uint32, format string, a ...interface{}) error {
  131. return l.send(l.ev.Warning(eventID, fmt.Sprintf(format, a...)))
  132. }
  133. // NInfof logs an info message and an event ID.
  134. func (l WindowsLogger) NInfof(eventID uint32, format string, a ...interface{}) error {
  135. return l.send(l.ev.Info(eventID, fmt.Sprintf(format, a...)))
  136. }
  137. var interactive = false
  138. func init() {
  139. var err error
  140. interactive, err = svc.IsAnInteractiveSession()
  141. if err != nil {
  142. panic(err)
  143. }
  144. }
  145. func (ws *windowsService) String() string {
  146. if len(ws.DisplayName) > 0 {
  147. return ws.DisplayName
  148. }
  149. return ws.Name
  150. }
  151. func (ws *windowsService) setError(err error) {
  152. ws.errSync.Lock()
  153. defer ws.errSync.Unlock()
  154. ws.stopStartErr = err
  155. }
  156. func (ws *windowsService) getError() error {
  157. ws.errSync.Lock()
  158. defer ws.errSync.Unlock()
  159. return ws.stopStartErr
  160. }
  161. func (ws *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) {
  162. const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
  163. changes <- svc.Status{State: svc.StartPending}
  164. if err := ws.i.Start(ws); err != nil {
  165. ws.setError(err)
  166. return true, 1
  167. }
  168. changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
  169. loop:
  170. for {
  171. c := <-r
  172. switch c.Cmd {
  173. case svc.Interrogate:
  174. changes <- c.CurrentStatus
  175. case svc.Stop, svc.Shutdown:
  176. changes <- svc.Status{State: svc.StopPending}
  177. if err := ws.i.Stop(ws); err != nil {
  178. ws.setError(err)
  179. return true, 2
  180. }
  181. break loop
  182. default:
  183. continue loop
  184. }
  185. }
  186. return false, 0
  187. }
  188. func (ws *windowsService) Install() error {
  189. exepath, err := ws.execPath()
  190. if err != nil {
  191. return err
  192. }
  193. m, err := mgr.Connect()
  194. if err != nil {
  195. return err
  196. }
  197. defer m.Disconnect()
  198. s, err := m.OpenService(ws.Name)
  199. if err == nil {
  200. s.Close()
  201. return fmt.Errorf("service %s already exists", ws.Name)
  202. }
  203. s, err = m.CreateService(ws.Name, exepath, mgr.Config{
  204. DisplayName: ws.DisplayName,
  205. Description: ws.Description,
  206. StartType: mgr.StartAutomatic,
  207. ServiceStartName: ws.UserName,
  208. Password: ws.Option.string("Password", ""),
  209. Dependencies: ws.Dependencies,
  210. }, ws.Arguments...)
  211. if err != nil {
  212. return err
  213. }
  214. defer s.Close()
  215. err = eventlog.InstallAsEventCreate(ws.Name, eventlog.Error|eventlog.Warning|eventlog.Info)
  216. if err != nil {
  217. s.Delete()
  218. return fmt.Errorf("InstallAsEventCreate() failed: %s", err)
  219. }
  220. // penggy add for config restart on crash
  221. err = setServiceFailureActions(s.Handle)
  222. if err != nil {
  223. panic(err)
  224. }
  225. //-- penggy add for config restart on crash
  226. return nil
  227. }
  228. func (ws *windowsService) Uninstall() error {
  229. m, err := mgr.Connect()
  230. if err != nil {
  231. return err
  232. }
  233. defer m.Disconnect()
  234. s, err := m.OpenService(ws.Name)
  235. if err != nil {
  236. return fmt.Errorf("service %s is not installed", ws.Name)
  237. }
  238. defer s.Close()
  239. err = s.Delete()
  240. if err != nil {
  241. return err
  242. }
  243. err = eventlog.Remove(ws.Name)
  244. if err != nil {
  245. return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
  246. }
  247. return nil
  248. }
  249. func (ws *windowsService) Run() error {
  250. ws.setError(nil)
  251. if !interactive {
  252. // Return error messages from start and stop routines
  253. // that get executed in the Execute method.
  254. // Guarded with a mutex as it may run a different thread
  255. // (callback from windows).
  256. runErr := svc.Run(ws.Name, ws)
  257. startStopErr := ws.getError()
  258. if startStopErr != nil {
  259. return startStopErr
  260. }
  261. if runErr != nil {
  262. return runErr
  263. }
  264. return nil
  265. }
  266. err := ws.i.Start(ws)
  267. if err != nil {
  268. return err
  269. }
  270. sigChan := make(chan os.Signal)
  271. signal.Notify(sigChan, os.Interrupt, os.Kill)
  272. <-sigChan
  273. return ws.i.Stop(ws)
  274. }
  275. func (ws *windowsService) Start() error {
  276. m, err := mgr.Connect()
  277. if err != nil {
  278. return err
  279. }
  280. defer m.Disconnect()
  281. s, err := m.OpenService(ws.Name)
  282. if err != nil {
  283. return err
  284. }
  285. defer s.Close()
  286. return s.Start()
  287. }
  288. func (ws *windowsService) Stop() error {
  289. m, err := mgr.Connect()
  290. if err != nil {
  291. return err
  292. }
  293. defer m.Disconnect()
  294. s, err := m.OpenService(ws.Name)
  295. if err != nil {
  296. return err
  297. }
  298. defer s.Close()
  299. return ws.stopWait(s)
  300. }
  301. func (ws *windowsService) Restart() error {
  302. m, err := mgr.Connect()
  303. if err != nil {
  304. return err
  305. }
  306. defer m.Disconnect()
  307. s, err := m.OpenService(ws.Name)
  308. if err != nil {
  309. return err
  310. }
  311. defer s.Close()
  312. err = ws.stopWait(s)
  313. if err != nil {
  314. return err
  315. }
  316. return s.Start()
  317. }
  318. func (ws *windowsService) stopWait(s *mgr.Service) error {
  319. // First stop the service. Then wait for the service to
  320. // actually stop before starting it.
  321. status, err := s.Control(svc.Stop)
  322. if err != nil {
  323. return err
  324. }
  325. timeDuration := time.Millisecond * 50
  326. timeout := time.After(getStopTimeout() + (timeDuration * 2))
  327. tick := time.NewTicker(timeDuration)
  328. defer tick.Stop()
  329. for status.State != svc.Stopped {
  330. select {
  331. case <-tick.C:
  332. status, err = s.Query()
  333. if err != nil {
  334. return err
  335. }
  336. case <-timeout:
  337. break
  338. }
  339. }
  340. return nil
  341. }
  342. // getStopTimeout fetches the time before windows will kill the service.
  343. func getStopTimeout() time.Duration {
  344. // For default and paths see https://support.microsoft.com/en-us/kb/146092
  345. defaultTimeout := time.Millisecond * 20000
  346. key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control`, registry.READ)
  347. if err != nil {
  348. return defaultTimeout
  349. }
  350. sv, _, err := key.GetStringValue("WaitToKillServiceTimeout")
  351. if err != nil {
  352. return defaultTimeout
  353. }
  354. v, err := strconv.Atoi(sv)
  355. if err != nil {
  356. return defaultTimeout
  357. }
  358. return time.Millisecond * time.Duration(v)
  359. }
  360. func (ws *windowsService) Logger(errs chan<- error) (Logger, error) {
  361. if interactive {
  362. return ConsoleLogger, nil
  363. }
  364. return ws.SystemLogger(errs)
  365. }
  366. func (ws *windowsService) SystemLogger(errs chan<- error) (Logger, error) {
  367. el, err := eventlog.Open(ws.Name)
  368. if err != nil {
  369. return nil, err
  370. }
  371. return WindowsLogger{el, errs}, nil
  372. }