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