server.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. * DudelDu
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package dudeldu
  11. import (
  12. "log"
  13. "net"
  14. "os"
  15. "os/signal"
  16. "sync"
  17. "syscall"
  18. "time"
  19. )
  20. /*
  21. ProductVersion is the current version of DudelDu
  22. */
  23. const ProductVersion = "1.3.1"
  24. /*
  25. ConnectionHandler is a function to handle new connections
  26. */
  27. type ConnectionHandler func(net.Conn, net.Error)
  28. /*
  29. DebugLogger is the debug logging interface of the Server
  30. */
  31. type DebugLogger interface {
  32. /*
  33. IsDebugOutputEnabled returns true if debug output is enabled.
  34. */
  35. IsDebugOutputEnabled() bool
  36. /*
  37. PrintDebug will print debug output if `DebugOutput` is enabled.
  38. */
  39. PrintDebug(v ...interface{})
  40. }
  41. /*
  42. Server data structure
  43. */
  44. type Server struct {
  45. Running bool // Flag indicating if the server is running
  46. Handler ConnectionHandler // Handler function for new connections
  47. DebugOutput bool // Enable additional debugging output
  48. LogPrint func(v ...interface{}) // Print logger method.
  49. signalling chan os.Signal // Channel for receiving signals
  50. tcpListener *net.TCPListener // TCP listener which accepts connections
  51. serving bool // Internal flag indicating if the socket should be served
  52. wgStatus *sync.WaitGroup // Optional wait group which should be notified once the server has started
  53. }
  54. /*
  55. NewServer creates a new DudelDu server.
  56. */
  57. func NewServer(handler ConnectionHandler) *Server {
  58. return &Server{
  59. Running: false,
  60. Handler: handler,
  61. DebugOutput: false,
  62. LogPrint: log.Print,
  63. }
  64. }
  65. /*
  66. IsDebugOutputEnabled returns true if debug output is enabled.
  67. */
  68. func (ds *Server) IsDebugOutputEnabled() bool {
  69. return ds.DebugOutput
  70. }
  71. /*
  72. PrintDebug will print debug output if `DebugOutput` is enabled.
  73. */
  74. func (ds *Server) PrintDebug(v ...interface{}) {
  75. if ds.DebugOutput {
  76. ds.LogPrint(v...)
  77. }
  78. }
  79. /*
  80. Run starts the DudelDu Server which can be stopped via ^C (Control-C).
  81. laddr should be the local address which should be given to net.Listen.
  82. wgStatus is an optional wait group which will be notified once the server is listening
  83. and once the server has shutdown.
  84. This function will not return unless the server is shutdown.
  85. */
  86. func (ds *Server) Run(laddr string, wgStatus *sync.WaitGroup) error {
  87. // Create listener
  88. listener, err := net.Listen("tcp", laddr)
  89. if err != nil {
  90. if wgStatus != nil {
  91. wgStatus.Done()
  92. }
  93. return err
  94. }
  95. ds.tcpListener = listener.(*net.TCPListener)
  96. ds.wgStatus = wgStatus
  97. // Attach SIGINT handler - on unix and windows this is send
  98. // when the user presses ^C (Control-C).
  99. ds.signalling = make(chan os.Signal)
  100. signal.Notify(ds.signalling, syscall.SIGINT)
  101. // Put the serve call into a wait group so we can wait until shutdown
  102. // completed
  103. var wg sync.WaitGroup
  104. wg.Add(1)
  105. // Kick off the serve thread
  106. go func() {
  107. defer wg.Done()
  108. ds.Running = true
  109. ds.serv()
  110. }()
  111. for {
  112. // Listen for shutdown signal
  113. if ds.IsDebugOutputEnabled() {
  114. ds.PrintDebug("Listen for shutdown signal")
  115. }
  116. signal := <-ds.signalling
  117. if signal == syscall.SIGINT {
  118. // Shutdown the server
  119. ds.serving = false
  120. // Wait until the server has shut down
  121. wg.Wait()
  122. ds.Running = false
  123. break
  124. }
  125. }
  126. if wgStatus != nil {
  127. wgStatus.Done()
  128. }
  129. return nil
  130. }
  131. /*
  132. Shutdown sends a shutdown signal.
  133. */
  134. func (ds *Server) Shutdown() {
  135. if ds.serving {
  136. ds.signalling <- syscall.SIGINT
  137. }
  138. }
  139. /*
  140. serv waits for new connections and assigns a handler to them.
  141. */
  142. func (ds *Server) serv() {
  143. ds.serving = true
  144. for ds.serving {
  145. // Wait up to a second for a new connection
  146. ds.tcpListener.SetDeadline(time.Now().Add(time.Second))
  147. newConn, err := ds.tcpListener.Accept()
  148. // Notify wgStatus if it was specified
  149. if ds.wgStatus != nil {
  150. ds.wgStatus.Done()
  151. ds.wgStatus = nil
  152. }
  153. netErr, ok := err.(net.Error)
  154. // Check if got an error and notify an error handler
  155. if newConn != nil || (ok && !(netErr.Timeout() || netErr.Temporary())) {
  156. go ds.Handler(newConn, netErr)
  157. }
  158. }
  159. ds.tcpListener.Close()
  160. }