Capstan is a Golang web framework that shares some similarities with others in its segment.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
2.7KB

  1. // +build !windows
  2. package capstan
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "net"
  7. "os"
  8. "os/signal"
  9. "syscall"
  10. )
  11. func InitNetwork() (err error, errc chan error, close chan struct{}) {
  12. var env *fdenv
  13. fds = &fdmap{
  14. sockets: make(map[string]Listener),
  15. descriptors: make(map[string]uintptr),
  16. }
  17. errc = make(chan error, 1)
  18. close = make(chan struct{}, 1)
  19. enc := os.Getenv("CAPSTAN_SOCKETS")
  20. if enc != "" {
  21. err = json.Unmarshal([]byte(enc), &env)
  22. if err != nil {
  23. // Do error.
  24. }
  25. parentPID = env.ParentPID
  26. for _, socket := range env.Sockets {
  27. fds.descriptors[socket.Name] = socket.FD
  28. }
  29. if parentPID != 0 {
  30. if err = syscall.Kill(parentPID, syscall.SIGUSR1); err != nil {
  31. return
  32. }
  33. // TODO: We should check the state of the parent process to ensure
  34. // it actually has terminated.
  35. parentPID = 0
  36. }
  37. }
  38. go func() {
  39. hup := make(chan os.Signal, 1)
  40. signal.Notify(hup, syscall.SIGHUP)
  41. usr1 := make(chan os.Signal, 1)
  42. signal.Notify(usr1, syscall.SIGUSR1)
  43. interrupt := make(chan os.Signal, 1)
  44. signal.Notify(interrupt, os.Interrupt)
  45. signal.Notify(interrupt, syscall.SIGTERM)
  46. // TODO: Replace fragile signalling infrastructure with pipes.
  47. for {
  48. select {
  49. case <-hup:
  50. go func() {
  51. if err := prelaunchFunc(); err != nil {
  52. errc <- err
  53. return
  54. }
  55. err := Relaunch()
  56. if err != nil {
  57. errc <- err
  58. }
  59. }()
  60. if err != nil {
  61. errc <- err
  62. }
  63. case <-usr1:
  64. if parentPID == 0 {
  65. close <- struct{}{}
  66. } else {
  67. parentPID = 0
  68. }
  69. case <-interrupt:
  70. for name, listener := range fds.sockets {
  71. if _, ok := listener.(*net.UnixListener); ok {
  72. stat, err := os.Stat(name)
  73. if os.IsNotExist(err) {
  74. continue
  75. }
  76. if stat.Mode()&os.ModeSocket == os.ModeSocket {
  77. os.Remove(name)
  78. }
  79. }
  80. }
  81. close <- struct{}{}
  82. }
  83. }
  84. }()
  85. return
  86. }
  87. func Listen(network, addr string) (net.Listener, error) {
  88. if fd, ok := fds.descriptors[netKey(network, addr)]; ok {
  89. listener, err := resumeListener(network, addr, fd)
  90. if err != nil {
  91. return nil, err
  92. }
  93. if _, ok := listener.(Listener); ok {
  94. fds.addListener(listener.(Listener))
  95. return listener, nil
  96. }
  97. }
  98. listener, err := net.Listen(network, addr)
  99. if err != nil {
  100. return nil, err
  101. }
  102. if network == "unix" {
  103. ln, _ := listener.(*net.UnixListener)
  104. ln.SetUnlinkOnClose(false)
  105. }
  106. if _, ok := listener.(Listener); !ok {
  107. return nil, fmt.Errorf("listener does not implement the appropriate interface")
  108. }
  109. if err := fds.addListener(listener.(Listener)); err != nil {
  110. return nil, err
  111. }
  112. return listener, nil
  113. }
  114. func StopListening(listener net.Listener) error {
  115. fds.removeListener(listener)
  116. return listener.Close()
  117. }