command_server.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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. access sync.Mutex
  18. savedLines *list.List[string]
  19. subscriber *observable.Subscriber[string]
  20. observer *observable.Observer[string]
  21. }
  22. func NewCommandServer(sharedDirectory string) *CommandServer {
  23. server := &CommandServer{
  24. sockPath: filepath.Join(sharedDirectory, "command.sock"),
  25. savedLines: new(list.List[string]),
  26. subscriber: observable.NewSubscriber[string](128),
  27. }
  28. server.observer = observable.NewObserver[string](server.subscriber, 64)
  29. return server
  30. }
  31. func (s *CommandServer) Start() error {
  32. os.Remove(s.sockPath)
  33. listener, err := net.ListenUnix("unix", &net.UnixAddr{
  34. Name: s.sockPath,
  35. Net: "unix",
  36. })
  37. if err != nil {
  38. return err
  39. }
  40. go s.loopConnection(listener)
  41. return nil
  42. }
  43. func (s *CommandServer) Close() error {
  44. return s.listener.Close()
  45. }
  46. func (s *CommandServer) loopConnection(listener net.Listener) {
  47. for {
  48. conn, err := listener.Accept()
  49. if err != nil {
  50. return
  51. }
  52. go func() {
  53. hErr := s.handleConnection(conn)
  54. if hErr != nil && !E.IsClosed(err) {
  55. log.Warn("log-server: process connection: ", hErr)
  56. }
  57. }()
  58. }
  59. }
  60. func (s *CommandServer) handleConnection(conn net.Conn) error {
  61. defer conn.Close()
  62. var command uint8
  63. err := binary.Read(conn, binary.BigEndian, &command)
  64. if err != nil {
  65. return E.Cause(err, "read command")
  66. }
  67. switch int32(command) {
  68. case CommandLog:
  69. return s.handleLogConn(conn)
  70. case CommandStatus:
  71. return s.handleStatusConn(conn)
  72. default:
  73. return E.New("unknown command: ", command)
  74. }
  75. }