command_server.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package libbox
  2. import (
  3. "encoding/binary"
  4. "net"
  5. "os"
  6. "path/filepath"
  7. "sync"
  8. "github.com/sagernet/sing-box/log"
  9. "github.com/sagernet/sing/common"
  10. "github.com/sagernet/sing/common/debug"
  11. E "github.com/sagernet/sing/common/exceptions"
  12. "github.com/sagernet/sing/common/observable"
  13. "github.com/sagernet/sing/common/x/list"
  14. )
  15. type CommandServer struct {
  16. sockPath string
  17. listener net.Listener
  18. handler CommandServerHandler
  19. access sync.Mutex
  20. savedLines *list.List[string]
  21. subscriber *observable.Subscriber[string]
  22. observer *observable.Observer[string]
  23. }
  24. type CommandServerHandler interface {
  25. ServiceStop() error
  26. ServiceReload() error
  27. }
  28. func NewCommandServer(sharedDirectory string, handler CommandServerHandler) *CommandServer {
  29. server := &CommandServer{
  30. sockPath: filepath.Join(sharedDirectory, "command.sock"),
  31. handler: handler,
  32. savedLines: new(list.List[string]),
  33. subscriber: observable.NewSubscriber[string](128),
  34. }
  35. server.observer = observable.NewObserver[string](server.subscriber, 64)
  36. return server
  37. }
  38. func (s *CommandServer) Start() error {
  39. os.Remove(s.sockPath)
  40. listener, err := net.ListenUnix("unix", &net.UnixAddr{
  41. Name: s.sockPath,
  42. Net: "unix",
  43. })
  44. if err != nil {
  45. return err
  46. }
  47. s.listener = listener
  48. go s.loopConnection(listener)
  49. return nil
  50. }
  51. func (s *CommandServer) Close() error {
  52. return common.Close(
  53. s.listener,
  54. s.observer,
  55. )
  56. }
  57. func (s *CommandServer) loopConnection(listener net.Listener) {
  58. for {
  59. conn, err := listener.Accept()
  60. if err != nil {
  61. return
  62. }
  63. go func() {
  64. hErr := s.handleConnection(conn)
  65. if hErr != nil && !E.IsClosed(err) {
  66. if debug.Enabled {
  67. log.Warn("log-server: process connection: ", hErr)
  68. }
  69. }
  70. }()
  71. }
  72. }
  73. func (s *CommandServer) handleConnection(conn net.Conn) error {
  74. defer conn.Close()
  75. var command uint8
  76. err := binary.Read(conn, binary.BigEndian, &command)
  77. if err != nil {
  78. return E.Cause(err, "read command")
  79. }
  80. switch int32(command) {
  81. case CommandLog:
  82. return s.handleLogConn(conn)
  83. case CommandStatus:
  84. return s.handleStatusConn(conn)
  85. case CommandServiceStop:
  86. return s.handleServiceStop(conn)
  87. case CommandServiceReload:
  88. return s.handleServiceReload(conn)
  89. case CommandCloseConnections:
  90. return s.handleCloseConnections(conn)
  91. default:
  92. return E.New("unknown command: ", command)
  93. }
  94. }