github.com/sagernet/sing-box@v1.9.0-rc.20/box_outbound.go (about) 1 package box 2 3 import ( 4 "strings" 5 6 "github.com/sagernet/sing-box/adapter" 7 "github.com/sagernet/sing-box/common/taskmonitor" 8 C "github.com/sagernet/sing-box/constant" 9 "github.com/sagernet/sing/common" 10 E "github.com/sagernet/sing/common/exceptions" 11 F "github.com/sagernet/sing/common/format" 12 ) 13 14 func (s *Box) startOutbounds() error { 15 monitor := taskmonitor.New(s.logger, C.StartTimeout) 16 outboundTags := make(map[adapter.Outbound]string) 17 outbounds := make(map[string]adapter.Outbound) 18 for i, outboundToStart := range s.outbounds { 19 var outboundTag string 20 if outboundToStart.Tag() == "" { 21 outboundTag = F.ToString(i) 22 } else { 23 outboundTag = outboundToStart.Tag() 24 } 25 if _, exists := outbounds[outboundTag]; exists { 26 return E.New("outbound tag ", outboundTag, " duplicated") 27 } 28 outboundTags[outboundToStart] = outboundTag 29 outbounds[outboundTag] = outboundToStart 30 } 31 started := make(map[string]bool) 32 for { 33 canContinue := false 34 startOne: 35 for _, outboundToStart := range s.outbounds { 36 outboundTag := outboundTags[outboundToStart] 37 if started[outboundTag] { 38 continue 39 } 40 dependencies := outboundToStart.Dependencies() 41 for _, dependency := range dependencies { 42 if !started[dependency] { 43 continue startOne 44 } 45 } 46 started[outboundTag] = true 47 canContinue = true 48 if starter, isStarter := outboundToStart.(common.Starter); isStarter { 49 monitor.Start("initialize outbound/", outboundToStart.Type(), "[", outboundTag, "]") 50 err := starter.Start() 51 monitor.Finish() 52 if err != nil { 53 return E.Cause(err, "initialize outbound/", outboundToStart.Type(), "[", outboundTag, "]") 54 } 55 } 56 } 57 if len(started) == len(s.outbounds) { 58 break 59 } 60 if canContinue { 61 continue 62 } 63 currentOutbound := common.Find(s.outbounds, func(it adapter.Outbound) bool { 64 return !started[outboundTags[it]] 65 }) 66 var lintOutbound func(oTree []string, oCurrent adapter.Outbound) error 67 lintOutbound = func(oTree []string, oCurrent adapter.Outbound) error { 68 problemOutboundTag := common.Find(oCurrent.Dependencies(), func(it string) bool { 69 return !started[it] 70 }) 71 if common.Contains(oTree, problemOutboundTag) { 72 return E.New("circular outbound dependency: ", strings.Join(oTree, " -> "), " -> ", problemOutboundTag) 73 } 74 problemOutbound := outbounds[problemOutboundTag] 75 if problemOutbound == nil { 76 return E.New("dependency[", problemOutboundTag, "] not found for outbound[", outboundTags[oCurrent], "]") 77 } 78 return lintOutbound(append(oTree, problemOutboundTag), problemOutbound) 79 } 80 return lintOutbound([]string{outboundTags[currentOutbound]}, currentOutbound) 81 } 82 return nil 83 }