box.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. package box
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "os"
  7. "runtime/debug"
  8. "time"
  9. "github.com/sagernet/sing-box/adapter"
  10. "github.com/sagernet/sing-box/adapter/inbound"
  11. "github.com/sagernet/sing-box/adapter/outbound"
  12. "github.com/sagernet/sing-box/common/taskmonitor"
  13. C "github.com/sagernet/sing-box/constant"
  14. "github.com/sagernet/sing-box/experimental"
  15. "github.com/sagernet/sing-box/experimental/cachefile"
  16. "github.com/sagernet/sing-box/experimental/libbox/platform"
  17. "github.com/sagernet/sing-box/log"
  18. "github.com/sagernet/sing-box/option"
  19. "github.com/sagernet/sing-box/protocol/direct"
  20. "github.com/sagernet/sing-box/route"
  21. "github.com/sagernet/sing/common"
  22. E "github.com/sagernet/sing/common/exceptions"
  23. F "github.com/sagernet/sing/common/format"
  24. "github.com/sagernet/sing/service"
  25. "github.com/sagernet/sing/service/pause"
  26. )
  27. var _ adapter.Service = (*Box)(nil)
  28. type Box struct {
  29. createdAt time.Time
  30. router adapter.Router
  31. inbound *inbound.Manager
  32. outbound *outbound.Manager
  33. network *route.NetworkManager
  34. logFactory log.Factory
  35. logger log.ContextLogger
  36. preServices1 map[string]adapter.Service
  37. preServices2 map[string]adapter.Service
  38. postServices map[string]adapter.Service
  39. done chan struct{}
  40. }
  41. type Options struct {
  42. option.Options
  43. Context context.Context
  44. PlatformLogWriter log.PlatformWriter
  45. }
  46. func Context(ctx context.Context, inboundRegistry adapter.InboundRegistry, outboundRegistry adapter.OutboundRegistry) context.Context {
  47. if service.FromContext[option.InboundOptionsRegistry](ctx) == nil ||
  48. service.FromContext[adapter.InboundRegistry](ctx) == nil {
  49. ctx = service.ContextWith[option.InboundOptionsRegistry](ctx, inboundRegistry)
  50. ctx = service.ContextWith[adapter.InboundRegistry](ctx, inboundRegistry)
  51. }
  52. if service.FromContext[option.OutboundOptionsRegistry](ctx) == nil ||
  53. service.FromContext[adapter.OutboundRegistry](ctx) == nil {
  54. ctx = service.ContextWith[option.OutboundOptionsRegistry](ctx, outboundRegistry)
  55. ctx = service.ContextWith[adapter.OutboundRegistry](ctx, outboundRegistry)
  56. }
  57. return ctx
  58. }
  59. func New(options Options) (*Box, error) {
  60. createdAt := time.Now()
  61. ctx := options.Context
  62. if ctx == nil {
  63. ctx = context.Background()
  64. }
  65. ctx = service.ContextWithDefaultRegistry(ctx)
  66. inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
  67. if inboundRegistry == nil {
  68. return nil, E.New("missing inbound registry in context")
  69. }
  70. outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
  71. if outboundRegistry == nil {
  72. return nil, E.New("missing outbound registry in context")
  73. }
  74. ctx = pause.WithDefaultManager(ctx)
  75. experimentalOptions := common.PtrValueOrDefault(options.Experimental)
  76. applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
  77. var needCacheFile bool
  78. var needClashAPI bool
  79. var needV2RayAPI bool
  80. if experimentalOptions.CacheFile != nil && experimentalOptions.CacheFile.Enabled || options.PlatformLogWriter != nil {
  81. needCacheFile = true
  82. }
  83. if experimentalOptions.ClashAPI != nil || options.PlatformLogWriter != nil {
  84. needClashAPI = true
  85. }
  86. if experimentalOptions.V2RayAPI != nil && experimentalOptions.V2RayAPI.Listen != "" {
  87. needV2RayAPI = true
  88. }
  89. platformInterface := service.FromContext[platform.Interface](ctx)
  90. var defaultLogWriter io.Writer
  91. if platformInterface != nil {
  92. defaultLogWriter = io.Discard
  93. }
  94. logFactory, err := log.New(log.Options{
  95. Context: ctx,
  96. Options: common.PtrValueOrDefault(options.Log),
  97. Observable: needClashAPI,
  98. DefaultWriter: defaultLogWriter,
  99. BaseTime: createdAt,
  100. PlatformWriter: options.PlatformLogWriter,
  101. })
  102. if err != nil {
  103. return nil, E.Cause(err, "create log factory")
  104. }
  105. routeOptions := common.PtrValueOrDefault(options.Route)
  106. inboundManager := inbound.NewManager(logFactory.NewLogger("inbound"), inboundRegistry)
  107. outboundManager := outbound.NewManager(logFactory.NewLogger("outbound"), outboundRegistry, routeOptions.Final)
  108. ctx = service.ContextWith[adapter.InboundManager](ctx, inboundManager)
  109. ctx = service.ContextWith[adapter.OutboundManager](ctx, outboundManager)
  110. networkManager, err := route.NewNetworkManager(ctx, logFactory.NewLogger("network"), routeOptions)
  111. if err != nil {
  112. return nil, E.Cause(err, "initialize network manager")
  113. }
  114. ctx = service.ContextWith[adapter.NetworkManager](ctx, networkManager)
  115. router, err := route.NewRouter(ctx, logFactory, routeOptions, common.PtrValueOrDefault(options.DNS), common.PtrValueOrDefault(options.NTP))
  116. if err != nil {
  117. return nil, E.Cause(err, "initialize router")
  118. }
  119. for i, inboundOptions := range options.Inbounds {
  120. var tag string
  121. if inboundOptions.Tag != "" {
  122. tag = inboundOptions.Tag
  123. } else {
  124. tag = F.ToString(i)
  125. }
  126. err = inboundManager.Create(ctx,
  127. router,
  128. logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
  129. tag,
  130. inboundOptions.Type,
  131. inboundOptions.Options,
  132. )
  133. if err != nil {
  134. return nil, E.Cause(err, "initialize inbound[", i, "]")
  135. }
  136. }
  137. for i, outboundOptions := range options.Outbounds {
  138. var tag string
  139. if outboundOptions.Tag != "" {
  140. tag = outboundOptions.Tag
  141. } else {
  142. tag = F.ToString(i)
  143. }
  144. outboundCtx := ctx
  145. if tag != "" {
  146. // TODO: remove this
  147. outboundCtx = adapter.WithContext(outboundCtx, &adapter.InboundContext{
  148. Outbound: tag,
  149. })
  150. }
  151. err = outboundManager.Create(
  152. outboundCtx,
  153. router,
  154. logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
  155. tag,
  156. outboundOptions.Type,
  157. outboundOptions.Options,
  158. )
  159. if err != nil {
  160. return nil, E.Cause(err, "initialize outbound[", i, "]")
  161. }
  162. }
  163. outboundManager.Initialize(common.Must1(
  164. direct.NewOutbound(
  165. ctx,
  166. router,
  167. logFactory.NewLogger("outbound/direct"),
  168. "direct",
  169. option.DirectOutboundOptions{},
  170. ),
  171. ))
  172. if platformInterface != nil {
  173. err = platformInterface.Initialize(networkManager)
  174. if err != nil {
  175. return nil, E.Cause(err, "initialize platform interface")
  176. }
  177. }
  178. preServices1 := make(map[string]adapter.Service)
  179. preServices2 := make(map[string]adapter.Service)
  180. postServices := make(map[string]adapter.Service)
  181. if needCacheFile {
  182. cacheFile := service.FromContext[adapter.CacheFile](ctx)
  183. if cacheFile == nil {
  184. cacheFile = cachefile.New(ctx, common.PtrValueOrDefault(experimentalOptions.CacheFile))
  185. service.MustRegister[adapter.CacheFile](ctx, cacheFile)
  186. }
  187. preServices1["cache file"] = cacheFile
  188. }
  189. if needClashAPI {
  190. clashAPIOptions := common.PtrValueOrDefault(experimentalOptions.ClashAPI)
  191. clashAPIOptions.ModeList = experimental.CalculateClashModeList(options.Options)
  192. clashServer, err := experimental.NewClashServer(ctx, logFactory.(log.ObservableFactory), clashAPIOptions)
  193. if err != nil {
  194. return nil, E.Cause(err, "create clash api server")
  195. }
  196. router.SetClashServer(clashServer)
  197. preServices2["clash api"] = clashServer
  198. }
  199. if needV2RayAPI {
  200. v2rayServer, err := experimental.NewV2RayServer(logFactory.NewLogger("v2ray-api"), common.PtrValueOrDefault(experimentalOptions.V2RayAPI))
  201. if err != nil {
  202. return nil, E.Cause(err, "create v2ray api server")
  203. }
  204. router.SetV2RayServer(v2rayServer)
  205. preServices2["v2ray api"] = v2rayServer
  206. }
  207. return &Box{
  208. router: router,
  209. inbound: inboundManager,
  210. outbound: outboundManager,
  211. network: networkManager,
  212. createdAt: createdAt,
  213. logFactory: logFactory,
  214. logger: logFactory.Logger(),
  215. preServices1: preServices1,
  216. preServices2: preServices2,
  217. postServices: postServices,
  218. done: make(chan struct{}),
  219. }, nil
  220. }
  221. func (s *Box) PreStart() error {
  222. err := s.preStart()
  223. if err != nil {
  224. // TODO: remove catch error
  225. defer func() {
  226. v := recover()
  227. if v != nil {
  228. println(err.Error())
  229. debug.PrintStack()
  230. panic("panic on early close: " + fmt.Sprint(v))
  231. }
  232. }()
  233. s.Close()
  234. return err
  235. }
  236. s.logger.Info("sing-box pre-started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)")
  237. return nil
  238. }
  239. func (s *Box) Start() error {
  240. err := s.start()
  241. if err != nil {
  242. // TODO: remove catch error
  243. defer func() {
  244. v := recover()
  245. if v != nil {
  246. println(err.Error())
  247. debug.PrintStack()
  248. println("panic on early start: " + fmt.Sprint(v))
  249. }
  250. }()
  251. s.Close()
  252. return err
  253. }
  254. s.logger.Info("sing-box started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)")
  255. return nil
  256. }
  257. func (s *Box) preStart() error {
  258. monitor := taskmonitor.New(s.logger, C.StartTimeout)
  259. monitor.Start("start logger")
  260. err := s.logFactory.Start()
  261. monitor.Finish()
  262. if err != nil {
  263. return E.Cause(err, "start logger")
  264. }
  265. for serviceName, service := range s.preServices1 {
  266. if preService, isPreService := service.(adapter.LegacyPreStarter); isPreService {
  267. monitor.Start("pre-start ", serviceName)
  268. err := preService.PreStart()
  269. monitor.Finish()
  270. if err != nil {
  271. return E.Cause(err, "pre-start ", serviceName)
  272. }
  273. }
  274. }
  275. for serviceName, service := range s.preServices2 {
  276. if preService, isPreService := service.(adapter.LegacyPreStarter); isPreService {
  277. monitor.Start("pre-start ", serviceName)
  278. err := preService.PreStart()
  279. monitor.Finish()
  280. if err != nil {
  281. return E.Cause(err, "pre-start ", serviceName)
  282. }
  283. }
  284. }
  285. err = s.network.Start(adapter.StartStateInitialize)
  286. if err != nil {
  287. return E.Cause(err, "initialize network manager")
  288. }
  289. err = s.router.Start(adapter.StartStateInitialize)
  290. if err != nil {
  291. return E.Cause(err, "initialize router")
  292. }
  293. err = s.outbound.Start(adapter.StartStateStart)
  294. if err != nil {
  295. return err
  296. }
  297. err = s.network.Start(adapter.StartStateStart)
  298. if err != nil {
  299. return err
  300. }
  301. return s.router.Start(adapter.StartStateStart)
  302. }
  303. func (s *Box) start() error {
  304. err := s.preStart()
  305. if err != nil {
  306. return err
  307. }
  308. for serviceName, service := range s.preServices1 {
  309. err = service.Start()
  310. if err != nil {
  311. return E.Cause(err, "start ", serviceName)
  312. }
  313. }
  314. for serviceName, service := range s.preServices2 {
  315. err = service.Start()
  316. if err != nil {
  317. return E.Cause(err, "start ", serviceName)
  318. }
  319. }
  320. err = s.inbound.Start(adapter.StartStateStart)
  321. if err != nil {
  322. return err
  323. }
  324. for serviceName, service := range s.postServices {
  325. err := service.Start()
  326. if err != nil {
  327. return E.Cause(err, "start ", serviceName)
  328. }
  329. }
  330. err = s.outbound.Start(adapter.StartStatePostStart)
  331. if err != nil {
  332. return err
  333. }
  334. err = s.network.Start(adapter.StartStatePostStart)
  335. if err != nil {
  336. return err
  337. }
  338. err = s.router.Start(adapter.StartStatePostStart)
  339. if err != nil {
  340. return err
  341. }
  342. err = s.inbound.Start(adapter.StartStatePostStart)
  343. if err != nil {
  344. return err
  345. }
  346. err = s.network.Start(adapter.StartStateStarted)
  347. if err != nil {
  348. return err
  349. }
  350. err = s.router.Start(adapter.StartStateStarted)
  351. if err != nil {
  352. return err
  353. }
  354. err = s.outbound.Start(adapter.StartStateStarted)
  355. if err != nil {
  356. return err
  357. }
  358. err = s.inbound.Start(adapter.StartStateStarted)
  359. if err != nil {
  360. return err
  361. }
  362. return nil
  363. }
  364. func (s *Box) Close() error {
  365. select {
  366. case <-s.done:
  367. return os.ErrClosed
  368. default:
  369. close(s.done)
  370. }
  371. monitor := taskmonitor.New(s.logger, C.StopTimeout)
  372. var errors error
  373. for serviceName, service := range s.postServices {
  374. monitor.Start("close ", serviceName)
  375. errors = E.Append(errors, service.Close(), func(err error) error {
  376. return E.Cause(err, "close ", serviceName)
  377. })
  378. monitor.Finish()
  379. }
  380. errors = E.Errors(errors, s.inbound.Close())
  381. errors = E.Errors(errors, s.outbound.Close())
  382. errors = E.Errors(errors, s.network.Close())
  383. errors = E.Errors(errors, s.router.Close())
  384. for serviceName, service := range s.preServices1 {
  385. monitor.Start("close ", serviceName)
  386. errors = E.Append(errors, service.Close(), func(err error) error {
  387. return E.Cause(err, "close ", serviceName)
  388. })
  389. monitor.Finish()
  390. }
  391. for serviceName, service := range s.preServices2 {
  392. monitor.Start("close ", serviceName)
  393. errors = E.Append(errors, service.Close(), func(err error) error {
  394. return E.Cause(err, "close ", serviceName)
  395. })
  396. monitor.Finish()
  397. }
  398. if err := common.Close(s.logFactory); err != nil {
  399. errors = E.Append(errors, err, func(err error) error {
  400. return E.Cause(err, "close logger")
  401. })
  402. }
  403. return errors
  404. }
  405. func (s *Box) Inbound() adapter.InboundManager {
  406. return s.inbound
  407. }
  408. func (s *Box) Outbound() adapter.OutboundManager {
  409. return s.outbound
  410. }
  411. func (s *Box) Network() adapter.NetworkManager {
  412. return s.network
  413. }
  414. func (s *Box) Router() adapter.Router {
  415. return s.router
  416. }