diff --git a/app/proxy/proxy_test.go b/app/proxy/proxy_test.go index ee4cfbe66..14ded5686 100644 --- a/app/proxy/proxy_test.go +++ b/app/proxy/proxy_test.go @@ -1,6 +1,7 @@ package proxy_test import ( + "context" "testing" "v2ray.com/core/app" @@ -21,14 +22,17 @@ func TestProxyDial(t *testing.T) { assert := assert.On(t) space := app.NewSpace() + ctx := app.ContextWithSpace(context.Background(), space) assert.Error(space.AddApp(new(proxyman.OutboundConfig))) outboundManager := proxyman.OutboundHandlerManagerFromSpace(space) - common.Must(outboundManager.SetHandler("tag", freedom.New(&freedom.Config{}, space, &proxy.OutboundHandlerMeta{ + freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{ Tag: "tag", StreamSettings: &internet.StreamConfig{ Protocol: internet.TransportProtocol_TCP, }, - }))) + }), &freedom.Config{}) + assert.Error(err).IsNil() + common.Must(outboundManager.SetHandler("tag", freedom)) assert.Error(space.AddApp(new(Config))).IsNil() proxy := OutboundProxyFromSpace(space) diff --git a/app/space.go b/app/space.go index 371f108f6..ed095b5c2 100644 --- a/app/space.go +++ b/app/space.go @@ -1,6 +1,8 @@ package app import ( + "context" + "github.com/golang/protobuf/proto" "v2ray.com/core/common/errors" "v2ray.com/core/common/log" @@ -104,3 +106,17 @@ func (v *spaceImpl) AddApp(config proto.Message) error { func (v *spaceImpl) AddAppLegacy(name string, application Application) { v.cache[name] = application } + +type contextKey int + +const ( + spaceKey = contextKey(0) +) + +func SpaceFromContext(ctx context.Context) Space { + return ctx.Value(spaceKey).(Space) +} + +func ContextWithSpace(ctx context.Context, space Space) context.Context { + return context.WithValue(ctx, spaceKey, space) +} diff --git a/inbound_detour_always.go b/inbound_detour_always.go index e1b5ba6c5..002428583 100644 --- a/inbound_detour_always.go +++ b/inbound_detour_always.go @@ -1,6 +1,8 @@ package core import ( + "context" + "v2ray.com/core/app" "v2ray.com/core/common/dice" "v2ray.com/core/common/log" @@ -15,7 +17,8 @@ type InboundDetourHandlerAlways struct { ich []proxy.InboundHandler } -func NewInboundDetourHandlerAlways(space app.Space, config *InboundConnectionConfig) (*InboundDetourHandlerAlways, error) { +func NewInboundDetourHandlerAlways(ctx context.Context, config *InboundConnectionConfig) (*InboundDetourHandlerAlways, error) { + space := app.SpaceFromContext(ctx) handler := &InboundDetourHandlerAlways{ space: space, config: config, @@ -27,13 +30,14 @@ func NewInboundDetourHandlerAlways(space app.Space, config *InboundConnectionCon if err != nil { return nil, err } - ich, err := proxy.CreateInboundHandler(config.Settings.Type, space, ichConfig, &proxy.InboundHandlerMeta{ + ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{ Address: config.GetListenOnValue(), Port: i, Tag: config.Tag, StreamSettings: config.StreamSettings, AllowPassiveConnection: config.AllowPassiveConnection, - }) + }), ichConfig) + if err != nil { log.Error("Failed to create inbound connection handler: ", err) return nil, err diff --git a/inbound_detour_dynamic.go b/inbound_detour_dynamic.go index 439c6b399..9f43fd383 100644 --- a/inbound_detour_dynamic.go +++ b/inbound_detour_dynamic.go @@ -4,6 +4,8 @@ import ( "sync" "time" + "context" + "v2ray.com/core/app" "v2ray.com/core/common/dice" "v2ray.com/core/common/log" @@ -20,13 +22,16 @@ type InboundDetourHandlerDynamic struct { ichs []proxy.InboundHandler ich2Recyle []proxy.InboundHandler lastRefresh time.Time + ctx context.Context } -func NewInboundDetourHandlerDynamic(space app.Space, config *InboundConnectionConfig) (*InboundDetourHandlerDynamic, error) { +func NewInboundDetourHandlerDynamic(ctx context.Context, config *InboundConnectionConfig) (*InboundDetourHandlerDynamic, error) { + space := app.SpaceFromContext(ctx) handler := &InboundDetourHandlerDynamic{ space: space, config: config, portsInUse: make(map[v2net.Port]bool), + ctx: ctx, } handler.ichs = make([]proxy.InboundHandler, config.GetAllocationStrategyValue().GetConcurrencyValue()) @@ -35,13 +40,13 @@ func NewInboundDetourHandlerDynamic(space app.Space, config *InboundConnectionCo if err != nil { return nil, err } - ich, err := proxy.CreateInboundHandler(config.Settings.Type, space, ichConfig, &proxy.InboundHandlerMeta{ + ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{ Address: config.GetListenOnValue(), Port: 0, Tag: config.Tag, StreamSettings: config.StreamSettings, AllowPassiveConnection: config.AllowPassiveConnection, - }) + }), ichConfig) if err != nil { log.Error("Point: Failed to create inbound connection handler: ", err) return nil, err @@ -107,8 +112,10 @@ func (v *InboundDetourHandlerDynamic) refresh() error { err := retry.Timed(5, 100).On(func() error { port := v.pickUnusedPort() ichConfig, _ := config.GetTypedSettings() - ich, err := proxy.CreateInboundHandler(config.Settings.Type, v.space, ichConfig, &proxy.InboundHandlerMeta{ - Address: config.GetListenOnValue(), Port: port, Tag: config.Tag, StreamSettings: config.StreamSettings}) + ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(v.ctx, &proxy.InboundHandlerMeta{ + Address: config.GetListenOnValue(), + Port: port, Tag: config.Tag, + StreamSettings: config.StreamSettings}), ichConfig) if err != nil { delete(v.portsInUse, port) return err diff --git a/proxy/blackhole/blackhole.go b/proxy/blackhole/blackhole.go index f702f58d5..85f36eab3 100644 --- a/proxy/blackhole/blackhole.go +++ b/proxy/blackhole/blackhole.go @@ -2,28 +2,26 @@ package blackhole import ( + "context" "time" - "v2ray.com/core/app" + "v2ray.com/core/common" v2net "v2ray.com/core/common/net" - "v2ray.com/core/proxy" "v2ray.com/core/transport/ray" ) // Handler is an outbound connection that sliently swallow the entire payload. type Handler struct { - meta *proxy.OutboundHandlerMeta response ResponseConfig } // New creates a new blackhole handler. -func New(space app.Space, config *Config, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { +func New(ctx context.Context, config *Config) (*Handler, error) { response, err := config.GetInternalResponse() if err != nil { return nil, err } return &Handler{ - meta: meta, response: response, }, nil } @@ -38,10 +36,8 @@ func (v *Handler) Dispatch(destination v2net.Destination, ray ray.OutboundRay) { ray.OutboundOutput().CloseError() } -// Factory is an utility for creating blackhole handlers. -type Factory struct{} - -// Create implements OutboundHandlerFactory.Create(). -func (v *Factory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { - return New(space, config.(*Config), meta) +func init() { + common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return New(ctx, config.(*Config)) + })) } diff --git a/proxy/blackhole/init.go b/proxy/blackhole/init.go deleted file mode 100644 index d0f54372e..000000000 --- a/proxy/blackhole/init.go +++ /dev/null @@ -1,12 +0,0 @@ -package blackhole - -import ( - "v2ray.com/core/common" - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy" -) - -func init() { - // Must listed after config.pb.go - common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory))) -} diff --git a/proxy/context.go b/proxy/context.go new file mode 100644 index 000000000..49d7784d0 --- /dev/null +++ b/proxy/context.go @@ -0,0 +1,36 @@ +package proxy + +import ( + "context" +) + +type key int + +const ( + inboundMetaKey = key(0) + outboundMetaKey = key(1) +) + +func ContextWithInboundMeta(ctx context.Context, meta *InboundHandlerMeta) context.Context { + return context.WithValue(ctx, inboundMetaKey, meta) +} + +func InboundMetaFromContext(ctx context.Context) *InboundHandlerMeta { + v := ctx.Value(inboundMetaKey) + if v == nil { + return nil + } + return v.(*InboundHandlerMeta) +} + +func ContextWithOutboundMeta(ctx context.Context, meta *OutboundHandlerMeta) context.Context { + return context.WithValue(ctx, outboundMetaKey, meta) +} + +func OutboundMetaFromContext(ctx context.Context) *OutboundHandlerMeta { + v := ctx.Value(outboundMetaKey) + if v == nil { + return nil + } + return v.(*OutboundHandlerMeta) +} diff --git a/proxy/creator.go b/proxy/creator.go deleted file mode 100644 index 3fe341efc..000000000 --- a/proxy/creator.go +++ /dev/null @@ -1,11 +0,0 @@ -package proxy - -import "v2ray.com/core/app" - -type InboundHandlerFactory interface { - Create(space app.Space, config interface{}, meta *InboundHandlerMeta) (InboundHandler, error) -} - -type OutboundHandlerFactory interface { - Create(space app.Space, config interface{}, meta *OutboundHandlerMeta) (OutboundHandler, error) -} diff --git a/proxy/dokodemo/dokodemo.go b/proxy/dokodemo/dokodemo.go index db1211fc6..75f3b8cc4 100644 --- a/proxy/dokodemo/dokodemo.go +++ b/proxy/dokodemo/dokodemo.go @@ -1,6 +1,7 @@ package dokodemo import ( + "context" "sync" "v2ray.com/core/app" @@ -10,7 +11,6 @@ import ( "v2ray.com/core/common/errors" "v2ray.com/core/common/log" v2net "v2ray.com/core/common/net" - "v2ray.com/core/common/serial" "v2ray.com/core/common/signal" "v2ray.com/core/proxy" "v2ray.com/core/transport/internet" @@ -31,7 +31,15 @@ type DokodemoDoor struct { meta *proxy.InboundHandlerMeta } -func NewDokodemoDoor(config *Config, space app.Space, meta *proxy.InboundHandlerMeta) *DokodemoDoor { +func NewDokodemoDoor(ctx context.Context, config *Config) (*DokodemoDoor, error) { + space := app.SpaceFromContext(ctx) + if space == nil { + return nil, errors.New("Dokodemo: No space in context.") + } + meta := proxy.InboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("Dokodemo: No outbound meta in context.") + } d := &DokodemoDoor{ config: config, address: config.GetPredefinedAddress(), @@ -45,7 +53,7 @@ func NewDokodemoDoor(config *Config, space app.Space, meta *proxy.InboundHandler } return nil }) - return d + return d, nil } func (v *DokodemoDoor) Port() v2net.Port { @@ -205,12 +213,8 @@ func (v *DokodemoDoor) HandleTCPConnection(conn internet.Connection) { } } -type Factory struct{} - -func (v *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { - return NewDokodemoDoor(rawConfig.(*Config), space, meta), nil -} - func init() { - common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory))) + common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return NewDokodemoDoor(ctx, config.(*Config)) + })) } diff --git a/proxy/dokodemo/dokodemo_test.go b/proxy/dokodemo/dokodemo_test.go index 1ec70cbd8..2047c0de9 100644 --- a/proxy/dokodemo/dokodemo_test.go +++ b/proxy/dokodemo/dokodemo_test.go @@ -4,6 +4,8 @@ import ( "net" "testing" + "context" + "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" _ "v2ray.com/core/app/dispatcher/impl" @@ -42,31 +44,36 @@ func TestDokodemoTCP(t *testing.T) { space.AddApp(new(proxyman.OutboundConfig)) ohm := proxyman.OutboundHandlerManagerFromSpace(space) - ohm.SetDefaultHandler( - freedom.New( - &freedom.Config{}, - space, - &proxy.OutboundHandlerMeta{ - Address: v2net.LocalHostIP, - StreamSettings: &internet.StreamConfig{ - Protocol: internet.TransportProtocol_TCP, - }, - })) + ctx := context.Background() + ctx = app.ContextWithSpace(ctx, space) + + freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{ + Address: v2net.LocalHostIP, + StreamSettings: &internet.StreamConfig{ + Protocol: internet.TransportProtocol_TCP, + }, + }), &freedom.Config{}) + assert.Error(err).IsNil() + ohm.SetDefaultHandler(freedom) data2Send := "Data to be sent to remote." port := v2net.Port(dice.Roll(20000) + 10000) - dokodemo := NewDokodemoDoor(&Config{ - Address: v2net.NewIPOrDomain(v2net.LocalHostIP), - Port: uint32(tcpServer.Port), - NetworkList: v2net.Network_TCP.AsList(), - Timeout: 600, - }, space, &proxy.InboundHandlerMeta{ + + ctx = proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{ Address: v2net.LocalHostIP, Port: port, StreamSettings: &internet.StreamConfig{ Protocol: internet.TransportProtocol_TCP, }}) + + dokodemo, err := NewDokodemoDoor(ctx, &Config{ + Address: v2net.NewIPOrDomain(v2net.LocalHostIP), + Port: uint32(tcpServer.Port), + NetworkList: v2net.Network_TCP.AsList(), + Timeout: 600, + }) + assert.Error(err).IsNil() defer dokodemo.Close() assert.Error(space.Initialize()).IsNil() @@ -114,30 +121,36 @@ func TestDokodemoUDP(t *testing.T) { space.AddApp(new(proxyman.OutboundConfig)) ohm := proxyman.OutboundHandlerManagerFromSpace(space) - ohm.SetDefaultHandler( - freedom.New( - &freedom.Config{}, - space, - &proxy.OutboundHandlerMeta{ - Address: v2net.AnyIP, - StreamSettings: &internet.StreamConfig{ - Protocol: internet.TransportProtocol_TCP, - }})) + + ctx := context.Background() + ctx = app.ContextWithSpace(ctx, space) + freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{ + Address: v2net.AnyIP, + StreamSettings: &internet.StreamConfig{ + Protocol: internet.TransportProtocol_TCP, + }, + }), &freedom.Config{}) + assert.Error(err).IsNil() + ohm.SetDefaultHandler(freedom) data2Send := "Data to be sent to remote." port := v2net.Port(dice.Roll(20000) + 10000) - dokodemo := NewDokodemoDoor(&Config{ - Address: v2net.NewIPOrDomain(v2net.LocalHostIP), - Port: uint32(udpServer.Port), - NetworkList: v2net.Network_UDP.AsList(), - Timeout: 600, - }, space, &proxy.InboundHandlerMeta{ + + ctx = proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{ Address: v2net.LocalHostIP, Port: port, StreamSettings: &internet.StreamConfig{ Protocol: internet.TransportProtocol_TCP, }}) + + dokodemo, err := NewDokodemoDoor(ctx, &Config{ + Address: v2net.NewIPOrDomain(v2net.LocalHostIP), + Port: uint32(udpServer.Port), + NetworkList: v2net.Network_UDP.AsList(), + Timeout: 600, + }) + assert.Error(err).IsNil() defer dokodemo.Close() assert.Error(space.Initialize()).IsNil() diff --git a/proxy/freedom/freedom.go b/proxy/freedom/freedom.go index 0bf57e905..7c78ba8b3 100644 --- a/proxy/freedom/freedom.go +++ b/proxy/freedom/freedom.go @@ -1,6 +1,7 @@ package freedom import ( + "context" "io" "v2ray.com/core/app" @@ -12,7 +13,6 @@ import ( "v2ray.com/core/common/log" v2net "v2ray.com/core/common/net" "v2ray.com/core/common/retry" - "v2ray.com/core/common/serial" "v2ray.com/core/common/signal" "v2ray.com/core/proxy" "v2ray.com/core/transport/internet" @@ -26,7 +26,15 @@ type Handler struct { meta *proxy.OutboundHandlerMeta } -func New(config *Config, space app.Space, meta *proxy.OutboundHandlerMeta) *Handler { +func New(ctx context.Context, config *Config) (*Handler, error) { + space := app.SpaceFromContext(ctx) + if space == nil { + return nil, errors.New("Freedom: No space in context.") + } + meta := proxy.OutboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("Freedom: No outbound meta in context.") + } f := &Handler{ domainStrategy: config.DomainStrategy, timeout: config.Timeout, @@ -41,7 +49,7 @@ func New(config *Config, space app.Space, meta *proxy.OutboundHandlerMeta) *Hand } return nil }) - return f + return f, nil } // Private: Visible for testing. @@ -128,12 +136,8 @@ func (v *Handler) Dispatch(destination v2net.Destination, ray ray.OutboundRay) { } } -type Factory struct{} - -func (v *Factory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { - return New(config.(*Config), space, meta), nil -} - func init() { - common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory))) + common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return New(ctx, config.(*Config)) + })) } diff --git a/proxy/freedom/freedom_test.go b/proxy/freedom/freedom_test.go index 0027bf089..f32d485c0 100644 --- a/proxy/freedom/freedom_test.go +++ b/proxy/freedom/freedom_test.go @@ -3,6 +3,8 @@ package freedom_test import ( "testing" + "context" + "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" _ "v2ray.com/core/app/dispatcher/impl" @@ -37,15 +39,15 @@ func TestSinglePacket(t *testing.T) { assert.Error(err).IsNil() space := app.NewSpace() - freedom := New( - &Config{}, - space, - &proxy.OutboundHandlerMeta{ - Address: v2net.AnyIP, - StreamSettings: &internet.StreamConfig{ - Protocol: internet.TransportProtocol_TCP, - }, - }) + ctx := app.ContextWithSpace(context.Background(), space) + ctx = proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{ + Address: v2net.AnyIP, + StreamSettings: &internet.StreamConfig{ + Protocol: internet.TransportProtocol_TCP, + }, + }) + freedom, err := New(ctx, &Config{}) + assert.Error(err).IsNil() assert.Error(space.Initialize()).IsNil() traffic := ray.NewRay() @@ -77,15 +79,15 @@ func TestIPResolution(t *testing.T) { }, })).IsNil() - freedom := New( - &Config{DomainStrategy: Config_USE_IP}, - space, - &proxy.OutboundHandlerMeta{ - Address: v2net.AnyIP, - StreamSettings: &internet.StreamConfig{ - Protocol: internet.TransportProtocol_TCP, - }, - }) + ctx := app.ContextWithSpace(context.Background(), space) + ctx = proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{ + Address: v2net.AnyIP, + StreamSettings: &internet.StreamConfig{ + Protocol: internet.TransportProtocol_TCP, + }, + }) + freedom, err := New(ctx, &Config{DomainStrategy: Config_USE_IP}) + assert.Error(err).IsNil() assert.Error(space.Initialize()).IsNil() diff --git a/proxy/handler_cache.go b/proxy/handler_cache.go index 3512ebab3..5c4bc1552 100644 --- a/proxy/handler_cache.go +++ b/proxy/handler_cache.go @@ -1,45 +1,34 @@ package proxy import ( - "v2ray.com/core/app" + "context" + "v2ray.com/core/common" "v2ray.com/core/common/errors" ) -var ( - inboundFactories = make(map[string]InboundHandlerFactory) - outboundFactories = make(map[string]OutboundHandlerFactory) -) - -func RegisterInboundHandlerCreator(name string, creator InboundHandlerFactory) error { - if _, found := inboundFactories[name]; found { - return common.ErrDuplicatedName +func CreateInboundHandler(ctx context.Context, config interface{}) (InboundHandler, error) { + handler, err := common.CreateObject(ctx, config) + if err != nil { + return nil, err + } + switch h := handler.(type) { + case InboundHandler: + return h, nil + default: + return nil, errors.New("Proxy: Not a InboundHandler.") } - inboundFactories[name] = creator - return nil } -func RegisterOutboundHandlerCreator(name string, creator OutboundHandlerFactory) error { - if _, found := outboundFactories[name]; found { - return common.ErrDuplicatedName +func CreateOutboundHandler(ctx context.Context, config interface{}) (OutboundHandler, error) { + handler, err := common.CreateObject(ctx, config) + if err != nil { + return nil, err } - outboundFactories[name] = creator - return nil -} - -func CreateInboundHandler(name string, space app.Space, config interface{}, meta *InboundHandlerMeta) (InboundHandler, error) { - creator, found := inboundFactories[name] - if !found { - return nil, errors.New("Proxy: Unknown inbound name: " + name) + switch h := handler.(type) { + case OutboundHandler: + return h, nil + default: + return nil, errors.New("Proxy: Not a OutboundHandler.") } - return creator.Create(space, config, meta) -} - -func CreateOutboundHandler(name string, space app.Space, config interface{}, meta *OutboundHandlerMeta) (OutboundHandler, error) { - creator, found := outboundFactories[name] - if !found { - return nil, errors.New("Proxy: Unknown outbound name: " + name) - } - - return creator.Create(space, config, meta) } diff --git a/proxy/http/server.go b/proxy/http/server.go index a2953340e..cbb4bcd79 100644 --- a/proxy/http/server.go +++ b/proxy/http/server.go @@ -8,6 +8,8 @@ import ( "strings" "sync" + "context" + "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" "v2ray.com/core/common" @@ -16,7 +18,6 @@ import ( "v2ray.com/core/common/errors" "v2ray.com/core/common/log" v2net "v2ray.com/core/common/net" - "v2ray.com/core/common/serial" "v2ray.com/core/common/signal" "v2ray.com/core/proxy" "v2ray.com/core/transport/internet" @@ -33,7 +34,15 @@ type Server struct { } // NewServer creates a new HTTP inbound handler. -func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandlerMeta) *Server { +func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { + space := app.SpaceFromContext(ctx) + if space == nil { + return nil, errors.New("HTTP|Server: No space in context.") + } + meta := proxy.InboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("HTTP|Server: No inbound meta from context.") + } s := &Server{ config: config, meta: meta, @@ -45,7 +54,7 @@ func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandler } return nil }) - return s + return s, nil } // Port implements InboundHandler.Port(). @@ -285,14 +294,8 @@ func (v *Server) handlePlainHTTP(request *http.Request, session *proxy.SessionIn } } -// ServerFactory is a InboundHandlerFactory. -type ServerFactory struct{} - -// Create implements InboundHandlerFactory.Create(). -func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { - return NewServer(rawConfig.(*ServerConfig), space, meta), nil -} - func init() { - common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(ServerConfig)), new(ServerFactory))) + common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return NewServer(ctx, config.(*ServerConfig)) + })) } diff --git a/proxy/shadowsocks/client.go b/proxy/shadowsocks/client.go index bdb578ad4..16544b9d5 100644 --- a/proxy/shadowsocks/client.go +++ b/proxy/shadowsocks/client.go @@ -1,7 +1,10 @@ package shadowsocks import ( - "v2ray.com/core/app" + "context" + "errors" + + "v2ray.com/core/common" "v2ray.com/core/common/buf" "v2ray.com/core/common/bufio" "v2ray.com/core/common/log" @@ -21,7 +24,11 @@ type Client struct { } // NewClient create a new Shadowsocks client. -func NewClient(config *ClientConfig, space app.Space, meta *proxy.OutboundHandlerMeta) (*Client, error) { +func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { + meta := proxy.OutboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("Shadowsocks|Client: No outbound meta in context.") + } serverList := protocol.NewServerList() for _, rec := range config.Server { serverList.AddServer(protocol.NewServerSpecFromPB(*rec)) @@ -164,10 +171,8 @@ func (v *Client) Dispatch(destination v2net.Destination, ray ray.OutboundRay) { } } -// ClientFactory is a OutboundHandlerFactory. -type ClientFactory struct{} - -// Create implements OutboundHandlerFactory.Create(). -func (ClientFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { - return NewClient(rawConfig.(*ClientConfig), space, meta) +func init() { + common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return NewClient(ctx, config.(*ClientConfig)) + })) } diff --git a/proxy/shadowsocks/init.go b/proxy/shadowsocks/init.go deleted file mode 100644 index 240174a4b..000000000 --- a/proxy/shadowsocks/init.go +++ /dev/null @@ -1,13 +0,0 @@ -package shadowsocks - -import ( - "v2ray.com/core/common" - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy" -) - -func init() { - // Must happen after config is initialized - common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType(new(ClientConfig)), new(ClientFactory))) - common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(ServerConfig)), new(ServerFactory))) -} diff --git a/proxy/shadowsocks/server.go b/proxy/shadowsocks/server.go index 4dc8c4814..7d8675909 100644 --- a/proxy/shadowsocks/server.go +++ b/proxy/shadowsocks/server.go @@ -1,8 +1,11 @@ package shadowsocks import ( + "context" + "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" + "v2ray.com/core/common" "v2ray.com/core/common/buf" "v2ray.com/core/common/bufio" "v2ray.com/core/common/errors" @@ -27,7 +30,15 @@ type Server struct { udpServer *udp.Server } -func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandlerMeta) (*Server, error) { +func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { + space := app.SpaceFromContext(ctx) + if space == nil { + return nil, errors.New("Shadowsocks|Server: No space in context.") + } + meta := proxy.InboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("Shadowsocks|Server: No inbound meta in context.") + } if config.GetUser() == nil { return nil, protocol.ErrUserMissing } @@ -216,8 +227,8 @@ func (v *Server) handleConnection(conn internet.Connection) { } } -type ServerFactory struct{} - -func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { - return NewServer(rawConfig.(*ServerConfig), space, meta) +func init() { + common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return NewServer(ctx, config.(*ServerConfig)) + })) } diff --git a/proxy/socks/client.go b/proxy/socks/client.go index cf6d1fd2e..339698dca 100644 --- a/proxy/socks/client.go +++ b/proxy/socks/client.go @@ -1,7 +1,10 @@ package socks import ( - "v2ray.com/core/app" + "context" + "errors" + + "v2ray.com/core/common" "v2ray.com/core/common/buf" "v2ray.com/core/common/log" "v2ray.com/core/common/net" @@ -18,7 +21,11 @@ type Client struct { meta *proxy.OutboundHandlerMeta } -func NewClient(config *ClientConfig, space app.Space, meta *proxy.OutboundHandlerMeta) (*Client, error) { +func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { + meta := proxy.OutboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("Socks|Client: No outbound meta in context.") + } serverList := protocol.NewServerList() for _, rec := range config.Server { serverList.AddServer(protocol.NewServerSpecFromPB(*rec)) @@ -112,8 +119,8 @@ func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) { } } -type ClientFactory struct{} - -func (ClientFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { - return NewClient(rawConfig.(*ClientConfig), space, meta) +func init() { + common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return NewClient(ctx, config.(*ClientConfig)) + })) } diff --git a/proxy/socks/server.go b/proxy/socks/server.go index 4ad56ae8f..707e1830e 100644 --- a/proxy/socks/server.go +++ b/proxy/socks/server.go @@ -1,12 +1,14 @@ package socks import ( + "context" "io" "sync" "time" "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" + "v2ray.com/core/common" "v2ray.com/core/common/buf" "v2ray.com/core/common/bufio" "v2ray.com/core/common/errors" @@ -34,7 +36,15 @@ type Server struct { } // NewServer creates a new Server object. -func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandlerMeta) *Server { +func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { + space := app.SpaceFromContext(ctx) + if space == nil { + return nil, errors.New("Socks|Server: No space in context.") + } + meta := proxy.InboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("Socks|Server: No inbound meta in context.") + } s := &Server{ config: config, meta: meta, @@ -46,7 +56,7 @@ func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandler } return nil }) - return s + return s, nil } // Port implements InboundHandler.Port(). @@ -181,8 +191,8 @@ func (v *Server) transport(reader io.Reader, writer io.Writer, session *proxy.Se } } -type ServerFactory struct{} - -func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { - return NewServer(rawConfig.(*ServerConfig), space, meta), nil +func init() { + common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return NewServer(ctx, config.(*ServerConfig)) + })) } diff --git a/proxy/socks/socks.go b/proxy/socks/socks.go index e89d90f53..2f885d391 100644 --- a/proxy/socks/socks.go +++ b/proxy/socks/socks.go @@ -1,12 +1,2 @@ +// Package socks provides implements of Socks protocol 4, 4a and 5. package socks - -import ( - "v2ray.com/core/common" - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy" -) - -func init() { - common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType((*ClientConfig)(nil)), new(ClientFactory))) - common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType((*ServerConfig)(nil)), new(ServerFactory))) -} diff --git a/proxy/vmess/inbound/inbound.go b/proxy/vmess/inbound/inbound.go index 927b2c17b..4fc387f53 100644 --- a/proxy/vmess/inbound/inbound.go +++ b/proxy/vmess/inbound/inbound.go @@ -4,6 +4,8 @@ import ( "io" "sync" + "context" + "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" "v2ray.com/core/app/proxyman" @@ -82,6 +84,43 @@ type VMessInboundHandler struct { meta *proxy.InboundHandlerMeta } +func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) { + space := app.SpaceFromContext(ctx) + if space == nil { + return nil, errors.New("VMess|Inbound: No space in context.") + } + meta := proxy.InboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("VMess|Inbound: No inbound meta in context.") + } + + allowedClients := vmess.NewTimedUserValidator(protocol.DefaultIDHash) + for _, user := range config.User { + allowedClients.Add(user) + } + + handler := &VMessInboundHandler{ + clients: allowedClients, + detours: config.Detour, + usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()), + meta: meta, + } + + space.OnInitialize(func() error { + handler.packetDispatcher = dispatcher.FromSpace(space) + if handler.packetDispatcher == nil { + return errors.New("VMess|Inbound: Dispatcher is not found in space.") + } + handler.inboundHandlerManager = proxyman.InboundHandlerManagerFromSpace(space) + if handler.inboundHandlerManager == nil { + return errors.New("VMess|Inbound: InboundHandlerManager is not found is space.") + } + return nil + }) + + return handler, nil +} + func (v *VMessInboundHandler) Port() v2net.Port { return v.meta.Port } @@ -251,38 +290,8 @@ func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) { } } -type Factory struct{} - -func (v *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { - config := rawConfig.(*Config) - - allowedClients := vmess.NewTimedUserValidator(protocol.DefaultIDHash) - for _, user := range config.User { - allowedClients.Add(user) - } - - handler := &VMessInboundHandler{ - clients: allowedClients, - detours: config.Detour, - usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()), - meta: meta, - } - - space.OnInitialize(func() error { - handler.packetDispatcher = dispatcher.FromSpace(space) - if handler.packetDispatcher == nil { - return errors.New("VMess|Inbound: Dispatcher is not found in space.") - } - handler.inboundHandlerManager = proxyman.InboundHandlerManagerFromSpace(space) - if handler.inboundHandlerManager == nil { - return errors.New("VMess|Inbound: InboundHandlerManager is not found is space.") - } - return nil - }) - - return handler, nil -} - func init() { - common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory))) + common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return New(ctx, config.(*Config)) + })) } diff --git a/proxy/vmess/outbound/outbound.go b/proxy/vmess/outbound/outbound.go index a2103669e..761f13478 100644 --- a/proxy/vmess/outbound/outbound.go +++ b/proxy/vmess/outbound/outbound.go @@ -3,6 +3,8 @@ package outbound import ( "time" + "context" + "v2ray.com/core/app" "v2ray.com/core/common" "v2ray.com/core/common/buf" @@ -12,7 +14,6 @@ import ( v2net "v2ray.com/core/common/net" "v2ray.com/core/common/protocol" "v2ray.com/core/common/retry" - "v2ray.com/core/common/serial" "v2ray.com/core/common/signal" "v2ray.com/core/proxy" "v2ray.com/core/proxy/vmess" @@ -28,6 +29,29 @@ type VMessOutboundHandler struct { meta *proxy.OutboundHandlerMeta } +func New(ctx context.Context, config *Config) (*VMessOutboundHandler, error) { + space := app.SpaceFromContext(ctx) + if space == nil { + return nil, errors.New("VMess|Outbound: No space in context.") + } + meta := proxy.OutboundMetaFromContext(ctx) + if meta == nil { + return nil, errors.New("VMess|Outbound: No outbound meta in context.") + } + + serverList := protocol.NewServerList() + for _, rec := range config.Receiver { + serverList.AddServer(protocol.NewServerSpecFromPB(*rec)) + } + handler := &VMessOutboundHandler{ + serverList: serverList, + serverPicker: protocol.NewRoundRobinServerPicker(serverList), + meta: meta, + } + + return handler, nil +} + // Dispatch implements OutboundHandler.Dispatch(). func (v *VMessOutboundHandler) Dispatch(target v2net.Destination, outboundRay ray.OutboundRay) { var rec *protocol.ServerSpec @@ -142,25 +166,8 @@ func (v *VMessOutboundHandler) Dispatch(target v2net.Destination, outboundRay ra return } -// Factory is a proxy factory for VMess outbound. -type Factory struct{} - -func (v *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { - vOutConfig := rawConfig.(*Config) - - serverList := protocol.NewServerList() - for _, rec := range vOutConfig.Receiver { - serverList.AddServer(protocol.NewServerSpecFromPB(*rec)) - } - handler := &VMessOutboundHandler{ - serverList: serverList, - serverPicker: protocol.NewRoundRobinServerPicker(serverList), - meta: meta, - } - - return handler, nil -} - func init() { - common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory))) + common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return New(ctx, config.(*Config)) + })) } diff --git a/v2ray.go b/v2ray.go index bd9e5ed0e..14d9cd9f6 100644 --- a/v2ray.go +++ b/v2ray.go @@ -1,6 +1,8 @@ package core import ( + "context" + "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" "v2ray.com/core/app/dns" @@ -38,6 +40,8 @@ func NewPoint(pConfig *Config) (*Point, error) { } space := app.NewSpace() + ctx := app.ContextWithSpace(context.Background(), space) + vpoint.space = space vpoint.space.AddAppLegacy(serial.GetMessageType((*proxyman.InboundConfig)(nil)), vpoint) @@ -94,14 +98,14 @@ func NewPoint(pConfig *Config) (*Point, error) { var inboundHandler InboundDetourHandler switch allocConfig.Type { case AllocationStrategy_Always: - dh, err := NewInboundDetourHandlerAlways(vpoint.space, inbound) + dh, err := NewInboundDetourHandlerAlways(ctx, inbound) if err != nil { log.Error("V2Ray: Failed to create detour handler: ", err) return nil, common.ErrBadConfiguration } inboundHandler = dh case AllocationStrategy_Random: - dh, err := NewInboundDetourHandlerDynamic(vpoint.space, inbound) + dh, err := NewInboundDetourHandlerDynamic(ctx, inbound) if err != nil { log.Error("V2Ray: Failed to create detour handler: ", err) return nil, common.ErrBadConfiguration @@ -124,13 +128,12 @@ func NewPoint(pConfig *Config) (*Point, error) { if err != nil { return nil, err } - outboundHandler, err := proxy.CreateOutboundHandler( - outbound.Settings.Type, vpoint.space, outboundSettings, &proxy.OutboundHandlerMeta{ - Tag: outbound.Tag, - Address: outbound.GetSendThroughValue(), - StreamSettings: outbound.StreamSettings, - ProxySettings: outbound.ProxySettings, - }) + outboundHandler, err := proxy.CreateOutboundHandler(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{ + Tag: outbound.Tag, + Address: outbound.GetSendThroughValue(), + StreamSettings: outbound.StreamSettings, + ProxySettings: outbound.ProxySettings, + }), outboundSettings) if err != nil { log.Error("V2Ray: Failed to create detour outbound connection handler: ", err) return nil, err