command_server.go 2.2 KB

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