github.com/xmplusdev/xray-core@v1.8.10/core/xray.go (about) 1 package core 2 3 import ( 4 "context" 5 "reflect" 6 "sync" 7 8 "github.com/xmplusdev/xray-core/common" 9 "github.com/xmplusdev/xray-core/common/platform" 10 "github.com/xmplusdev/xray-core/common/serial" 11 "github.com/xmplusdev/xray-core/features" 12 "github.com/xmplusdev/xray-core/features/dns" 13 "github.com/xmplusdev/xray-core/features/dns/localdns" 14 "github.com/xmplusdev/xray-core/features/inbound" 15 "github.com/xmplusdev/xray-core/features/outbound" 16 "github.com/xmplusdev/xray-core/features/policy" 17 "github.com/xmplusdev/xray-core/features/routing" 18 "github.com/xmplusdev/xray-core/features/stats" 19 "github.com/xmplusdev/xray-core/transport/internet" 20 ) 21 22 // Server is an instance of Xray. At any time, there must be at most one Server instance running. 23 type Server interface { 24 common.Runnable 25 } 26 27 // ServerType returns the type of the server. 28 func ServerType() interface{} { 29 return (*Instance)(nil) 30 } 31 32 type resolution struct { 33 deps []reflect.Type 34 callback interface{} 35 } 36 37 func getFeature(allFeatures []features.Feature, t reflect.Type) features.Feature { 38 for _, f := range allFeatures { 39 if reflect.TypeOf(f.Type()) == t { 40 return f 41 } 42 } 43 return nil 44 } 45 46 func (r *resolution) resolve(allFeatures []features.Feature) (bool, error) { 47 var fs []features.Feature 48 for _, d := range r.deps { 49 f := getFeature(allFeatures, d) 50 if f == nil { 51 return false, nil 52 } 53 fs = append(fs, f) 54 } 55 56 callback := reflect.ValueOf(r.callback) 57 var input []reflect.Value 58 callbackType := callback.Type() 59 for i := 0; i < callbackType.NumIn(); i++ { 60 pt := callbackType.In(i) 61 for _, f := range fs { 62 if reflect.TypeOf(f).AssignableTo(pt) { 63 input = append(input, reflect.ValueOf(f)) 64 break 65 } 66 } 67 } 68 69 if len(input) != callbackType.NumIn() { 70 panic("Can't get all input parameters") 71 } 72 73 var err error 74 ret := callback.Call(input) 75 errInterface := reflect.TypeOf((*error)(nil)).Elem() 76 for i := len(ret) - 1; i >= 0; i-- { 77 if ret[i].Type() == errInterface { 78 v := ret[i].Interface() 79 if v != nil { 80 err = v.(error) 81 } 82 break 83 } 84 } 85 86 return true, err 87 } 88 89 // Instance combines all functionalities in Xray. 90 type Instance struct { 91 access sync.Mutex 92 features []features.Feature 93 featureResolutions []resolution 94 running bool 95 96 ctx context.Context 97 } 98 99 func AddInboundHandler(server *Instance, config *InboundHandlerConfig) error { 100 inboundManager := server.GetFeature(inbound.ManagerType()).(inbound.Manager) 101 rawHandler, err := CreateObject(server, config) 102 if err != nil { 103 return err 104 } 105 handler, ok := rawHandler.(inbound.Handler) 106 if !ok { 107 return newError("not an InboundHandler") 108 } 109 if err := inboundManager.AddHandler(server.ctx, handler); err != nil { 110 return err 111 } 112 return nil 113 } 114 115 func addInboundHandlers(server *Instance, configs []*InboundHandlerConfig) error { 116 for _, inboundConfig := range configs { 117 if err := AddInboundHandler(server, inboundConfig); err != nil { 118 return err 119 } 120 } 121 122 return nil 123 } 124 125 func AddOutboundHandler(server *Instance, config *OutboundHandlerConfig) error { 126 outboundManager := server.GetFeature(outbound.ManagerType()).(outbound.Manager) 127 rawHandler, err := CreateObject(server, config) 128 if err != nil { 129 return err 130 } 131 handler, ok := rawHandler.(outbound.Handler) 132 if !ok { 133 return newError("not an OutboundHandler") 134 } 135 if err := outboundManager.AddHandler(server.ctx, handler); err != nil { 136 return err 137 } 138 return nil 139 } 140 141 func addOutboundHandlers(server *Instance, configs []*OutboundHandlerConfig) error { 142 for _, outboundConfig := range configs { 143 if err := AddOutboundHandler(server, outboundConfig); err != nil { 144 return err 145 } 146 } 147 148 return nil 149 } 150 151 // RequireFeatures is a helper function to require features from Instance in context. 152 // See Instance.RequireFeatures for more information. 153 func RequireFeatures(ctx context.Context, callback interface{}) error { 154 v := MustFromContext(ctx) 155 return v.RequireFeatures(callback) 156 } 157 158 // New returns a new Xray instance based on given configuration. 159 // The instance is not started at this point. 160 // To ensure Xray instance works properly, the config must contain one Dispatcher, one InboundHandlerManager and one OutboundHandlerManager. Other features are optional. 161 func New(config *Config) (*Instance, error) { 162 server := &Instance{ctx: context.Background()} 163 164 done, err := initInstanceWithConfig(config, server) 165 if done { 166 return nil, err 167 } 168 169 return server, nil 170 } 171 172 func NewWithContext(ctx context.Context, config *Config) (*Instance, error) { 173 server := &Instance{ctx: ctx} 174 175 done, err := initInstanceWithConfig(config, server) 176 if done { 177 return nil, err 178 } 179 180 return server, nil 181 } 182 183 func initInstanceWithConfig(config *Config, server *Instance) (bool, error) { 184 server.ctx = context.WithValue(server.ctx, "cone", 185 platform.NewEnvFlag(platform.UseCone).GetValue(func() string { return "" }) != "true") 186 187 if config.Transport != nil { 188 features.PrintDeprecatedFeatureWarning("global transport settings") 189 } 190 if err := config.Transport.Apply(); err != nil { 191 return true, err 192 } 193 194 for _, appSettings := range config.App { 195 settings, err := appSettings.GetInstance() 196 if err != nil { 197 return true, err 198 } 199 obj, err := CreateObject(server, settings) 200 if err != nil { 201 return true, err 202 } 203 if feature, ok := obj.(features.Feature); ok { 204 if err := server.AddFeature(feature); err != nil { 205 return true, err 206 } 207 } 208 } 209 210 essentialFeatures := []struct { 211 Type interface{} 212 Instance features.Feature 213 }{ 214 {dns.ClientType(), localdns.New()}, 215 {policy.ManagerType(), policy.DefaultManager{}}, 216 {routing.RouterType(), routing.DefaultRouter{}}, 217 {stats.ManagerType(), stats.NoopManager{}}, 218 } 219 220 for _, f := range essentialFeatures { 221 if server.GetFeature(f.Type) == nil { 222 if err := server.AddFeature(f.Instance); err != nil { 223 return true, err 224 } 225 } 226 } 227 228 internet.InitSystemDialer( 229 server.GetFeature(dns.ClientType()).(dns.Client), 230 func() outbound.Manager { 231 obm, _ := server.GetFeature(outbound.ManagerType()).(outbound.Manager) 232 return obm 233 }(), 234 ) 235 236 if server.featureResolutions != nil { 237 return true, newError("not all dependency are resolved.") 238 } 239 240 if err := addInboundHandlers(server, config.Inbound); err != nil { 241 return true, err 242 } 243 244 if err := addOutboundHandlers(server, config.Outbound); err != nil { 245 return true, err 246 } 247 return false, nil 248 } 249 250 // Type implements common.HasType. 251 func (s *Instance) Type() interface{} { 252 return ServerType() 253 } 254 255 // Close shutdown the Xray instance. 256 func (s *Instance) Close() error { 257 s.access.Lock() 258 defer s.access.Unlock() 259 260 s.running = false 261 262 var errors []interface{} 263 for _, f := range s.features { 264 if err := f.Close(); err != nil { 265 errors = append(errors, err) 266 } 267 } 268 if len(errors) > 0 { 269 return newError("failed to close all features").Base(newError(serial.Concat(errors...))) 270 } 271 272 return nil 273 } 274 275 // RequireFeatures registers a callback, which will be called when all dependent features are registered. 276 // The callback must be a func(). All its parameters must be features.Feature. 277 func (s *Instance) RequireFeatures(callback interface{}) error { 278 callbackType := reflect.TypeOf(callback) 279 if callbackType.Kind() != reflect.Func { 280 panic("not a function") 281 } 282 283 var featureTypes []reflect.Type 284 for i := 0; i < callbackType.NumIn(); i++ { 285 featureTypes = append(featureTypes, reflect.PtrTo(callbackType.In(i))) 286 } 287 288 r := resolution{ 289 deps: featureTypes, 290 callback: callback, 291 } 292 if finished, err := r.resolve(s.features); finished { 293 return err 294 } 295 s.featureResolutions = append(s.featureResolutions, r) 296 return nil 297 } 298 299 // AddFeature registers a feature into current Instance. 300 func (s *Instance) AddFeature(feature features.Feature) error { 301 s.features = append(s.features, feature) 302 303 if s.running { 304 if err := feature.Start(); err != nil { 305 newError("failed to start feature").Base(err).WriteToLog() 306 } 307 return nil 308 } 309 310 if s.featureResolutions == nil { 311 return nil 312 } 313 314 var pendingResolutions []resolution 315 for _, r := range s.featureResolutions { 316 finished, err := r.resolve(s.features) 317 if finished && err != nil { 318 return err 319 } 320 if !finished { 321 pendingResolutions = append(pendingResolutions, r) 322 } 323 } 324 if len(pendingResolutions) == 0 { 325 s.featureResolutions = nil 326 } else if len(pendingResolutions) < len(s.featureResolutions) { 327 s.featureResolutions = pendingResolutions 328 } 329 330 return nil 331 } 332 333 // GetFeature returns a feature of the given type, or nil if such feature is not registered. 334 func (s *Instance) GetFeature(featureType interface{}) features.Feature { 335 return getFeature(s.features, reflect.TypeOf(featureType)) 336 } 337 338 // Start starts the Xray instance, including all registered features. When Start returns error, the state of the instance is unknown. 339 // A Xray instance can be started only once. Upon closing, the instance is not guaranteed to start again. 340 // 341 // xray:api:stable 342 func (s *Instance) Start() error { 343 s.access.Lock() 344 defer s.access.Unlock() 345 346 s.running = true 347 for _, f := range s.features { 348 if err := f.Start(); err != nil { 349 return err 350 } 351 } 352 353 newError("Xray ", Version(), " started").AtWarning().WriteToLog() 354 355 return nil 356 }