server.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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. "net"
  13. "os"
  14. "os/signal"
  15. "sync"
  16. "syscall"
  17. "time"
  18. )
  19. /*
  20. ProductVersion is the current version of DudelDu
  21. */
  22. const ProductVersion = "0.0.0"
  23. /*
  24. ConnectionHandler is a function to handle new connections
  25. */
  26. type ConnectionHandler func(net.Conn, net.Error)
  27. /*
  28. Server data structure
  29. */
  30. type Server struct {
  31. Running bool // Flag indicating if the server is running
  32. Handler ConnectionHandler // Handler function for new connections
  33. signalling chan os.Signal // Channel for receiving signals
  34. tcpListener *net.TCPListener // TCP listener which accepts connections
  35. serving bool // Internal flag indicating if the socket should be served
  36. wgStatus *sync.WaitGroup // Optional wait group which should be notified once the server has started
  37. }
  38. /*
  39. NewServer creates a new DudelDu server.
  40. */
  41. func NewServer(handler ConnectionHandler) *Server {
  42. return &Server{
  43. Running: false,
  44. Handler: handler,
  45. }
  46. }
  47. /*
  48. Run starts the DudelDu Server which can be stopped via ^C (Control-C).
  49. laddr should be the local address which should be given to net.Listen.
  50. wgStatus is an optional wait group which will be notified once the server is listening
  51. and once the server has shutdown.
  52. This function will not return unless the server is shutdown.
  53. */
  54. func (ds *Server) Run(laddr string, wgStatus *sync.WaitGroup) error {
  55. // Create listener
  56. listener, err := net.Listen("tcp", laddr)
  57. if err != nil {
  58. if wgStatus != nil {
  59. wgStatus.Done()
  60. }
  61. return err
  62. }
  63. ds.tcpListener = listener.(*net.TCPListener)
  64. ds.wgStatus = wgStatus
  65. // Attach SIGINT handler - on unix and windows this is send
  66. // when the user presses ^C (Control-C).
  67. ds.signalling = make(chan os.Signal)
  68. signal.Notify(ds.signalling, syscall.SIGINT)
  69. // Put the serve call into a wait group so we can wait until shutdown
  70. // completed
  71. var wg sync.WaitGroup
  72. wg.Add(1)
  73. // Kick off the serve thread
  74. go func() {
  75. defer wg.Done()
  76. ds.Running = true
  77. ds.serv()
  78. }()
  79. for {
  80. // Listen for shutdown signal
  81. if DebugOutput {
  82. Print("Listen for shutdown signal")
  83. }
  84. signal := <-ds.signalling
  85. if signal == syscall.SIGINT {
  86. // Shutdown the server
  87. ds.serving = false
  88. // Wait until the server has shut down
  89. wg.Wait()
  90. ds.Running = false
  91. break
  92. }
  93. }
  94. if wgStatus != nil {
  95. wgStatus.Done()
  96. }
  97. return nil
  98. }
  99. /*
  100. Shutdown sends a shutdown signal.
  101. */
  102. func (ds *Server) Shutdown() {
  103. if ds.serving {
  104. ds.signalling <- syscall.SIGINT
  105. }
  106. }
  107. /*
  108. serv waits for new connections and assigns a handler to them.
  109. */
  110. func (ds *Server) serv() {
  111. ds.serving = true
  112. for ds.serving {
  113. // Wait up to a second for a new connection
  114. ds.tcpListener.SetDeadline(time.Now().Add(time.Second))
  115. newConn, err := ds.tcpListener.Accept()
  116. // Notify wgStatus if it was specified
  117. if ds.wgStatus != nil {
  118. ds.wgStatus.Done()
  119. ds.wgStatus = nil
  120. }
  121. netErr, ok := err.(net.Error)
  122. // Check if got an error and notify an error handler
  123. if newConn != nil || (ok && !(netErr.Timeout() || netErr.Temporary())) {
  124. go ds.Handler(newConn, netErr)
  125. }
  126. }
  127. ds.tcpListener.Close()
  128. }