Przeglądaj źródła

initializable apps

v2ray 9 lat temu
rodzic
commit
3ded18a75b

+ 22 - 8
app/dispatcher/impl/default.go

@@ -18,22 +18,36 @@ type DefaultDispatcher struct {
 }
 
 func NewDefaultDispatcher(space app.Space) *DefaultDispatcher {
+	d := &DefaultDispatcher{}
+	space.InitializeApplication(func() error {
+		return d.Initialize(space)
+	})
+	return d
+}
+
+// @Private
+func (this *DefaultDispatcher) Initialize(space app.Space) error {
 	if !space.HasApp(proxyman.APP_ID_OUTBOUND_MANAGER) {
 		log.Error("DefaultDispatcher: OutboundHandlerManager is not found in the space.")
-		return nil
+		return app.ErrorMissingApplication
 	}
+	this.ohm = space.GetApp(proxyman.APP_ID_OUTBOUND_MANAGER).(proxyman.OutboundHandlerManager)
+
 	if !space.HasApp(dns.APP_ID) {
 		log.Error("DefaultDispatcher: DNS is not found in the space.")
-		return nil
-	}
-	d := &DefaultDispatcher{
-		ohm: space.GetApp(proxyman.APP_ID_OUTBOUND_MANAGER).(proxyman.OutboundHandlerManager),
-		dns: space.GetApp(dns.APP_ID).(dns.Server),
+		return app.ErrorMissingApplication
 	}
+	this.dns = space.GetApp(dns.APP_ID).(dns.Server)
+
 	if space.HasApp(router.APP_ID) {
-		d.router = space.GetApp(router.APP_ID).(router.Router)
+		this.router = space.GetApp(router.APP_ID).(router.Router)
 	}
-	return d
+
+	return nil
+}
+
+func (this *DefaultDispatcher) Release() {
+
 }
 
 func (this *DefaultDispatcher) DispatchToOutbound(destination v2net.Destination) ray.InboundRay {

+ 20 - 7
app/dns/server.go

@@ -22,6 +22,7 @@ type DomainRecord struct {
 
 type CacheServer struct {
 	sync.RWMutex
+	space   app.Space
 	records map[string]*DomainRecord
 	servers []NameServer
 }
@@ -31,17 +32,29 @@ func NewCacheServer(space app.Space, config *Config) *CacheServer {
 		records: make(map[string]*DomainRecord),
 		servers: make([]NameServer, len(config.NameServers)),
 	}
-	dispatcher := space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
-	for idx, ns := range config.NameServers {
-		if ns.Address().IsDomain() && ns.Address().Domain() == "localhost" {
-			server.servers[idx] = &LocalNameServer{}
-		} else {
-			server.servers[idx] = NewUDPNameServer(ns, dispatcher)
+	space.InitializeApplication(func() error {
+		if !space.HasApp(dispatcher.APP_ID) {
+			log.Error("DNS: Dispatcher is not found in the space.")
+			return app.ErrorMissingApplication
 		}
-	}
+
+		dispatcher := space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
+		for idx, ns := range config.NameServers {
+			if ns.Address().IsDomain() && ns.Address().Domain() == "localhost" {
+				server.servers[idx] = &LocalNameServer{}
+			} else {
+				server.servers[idx] = NewUDPNameServer(ns, dispatcher)
+			}
+		}
+		return nil
+	})
 	return server
 }
 
+func (this *CacheServer) Release() {
+
+}
+
 //@Private
 func (this *CacheServer) GetCached(domain string) []net.IP {
 	this.RLock()

+ 4 - 2
app/dns/server_test.go

@@ -21,10 +21,9 @@ func TestDnsAdd(t *testing.T) {
 
 	space := app.NewSpace()
 
-	outboundHandlerManager := &proxyman.DefaultOutboundHandlerManager{}
+	outboundHandlerManager := proxyman.NewDefaultOutboundHandlerManager()
 	outboundHandlerManager.SetDefaultHandler(&freedom.FreedomConnection{})
 	space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager)
-
 	space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
 
 	domain := "local.v2ray.com"
@@ -33,6 +32,9 @@ func TestDnsAdd(t *testing.T) {
 			v2net.UDPDestination(v2net.IPAddress([]byte{8, 8, 8, 8}), v2net.Port(53)),
 		},
 	})
+	space.BindApp(APP_ID, server)
+	space.Initialize()
+
 	ips := server.Get(domain)
 	assert.Int(len(ips)).Equals(1)
 	netassert.IP(ips[0].To4()).Equals(net.IP([]byte{127, 0, 0, 1}))

+ 10 - 0
app/proxyman/proxyman.go

@@ -27,6 +27,16 @@ type DefaultOutboundHandlerManager struct {
 	taggedHandler  map[string]proxy.OutboundHandler
 }
 
+func NewDefaultOutboundHandlerManager() *DefaultOutboundHandlerManager {
+	return &DefaultOutboundHandlerManager{
+		taggedHandler: make(map[string]proxy.OutboundHandler),
+	}
+}
+
+func (this *DefaultOutboundHandlerManager) Release() {
+
+}
+
 func (this *DefaultOutboundHandlerManager) GetDefaultHandler() proxy.OutboundHandler {
 	this.RLock()
 	defer this.RUnlock()

+ 2 - 0
app/router/router.go

@@ -2,6 +2,7 @@ package router
 
 import (
 	"github.com/v2ray/v2ray-core/app"
+	"github.com/v2ray/v2ray-core/common"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 )
 
@@ -10,6 +11,7 @@ const (
 )
 
 type Router interface {
+	common.Releasable
 	TakeDetour(v2net.Destination) (string, error)
 }
 

+ 0 - 31
app/router/router_test.go

@@ -1,31 +0,0 @@
-package router_test
-
-import (
-	"net"
-	"path/filepath"
-	"testing"
-
-	. "github.com/v2ray/v2ray-core/app/router"
-	_ "github.com/v2ray/v2ray-core/app/router/rules"
-	v2net "github.com/v2ray/v2ray-core/common/net"
-	"github.com/v2ray/v2ray-core/shell/point"
-	v2testing "github.com/v2ray/v2ray-core/testing"
-	"github.com/v2ray/v2ray-core/testing/assert"
-)
-
-func TestRouter(t *testing.T) {
-	v2testing.Current(t)
-
-	baseDir := "$GOPATH/src/github.com/v2ray/v2ray-core/release/config"
-
-	pointConfig, err := point.LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json"))
-	assert.Error(err).IsNil()
-
-	router, err := CreateRouter(pointConfig.RouterConfig.Strategy, pointConfig.RouterConfig.Settings, nil)
-	assert.Error(err).IsNil()
-
-	dest := v2net.TCPDestination(v2net.IPAddress(net.ParseIP("120.135.126.1")), 80)
-	tag, err := router.TakeDetour(dest)
-	assert.Error(err).IsNil()
-	assert.StringLiteral(tag).Equals("direct")
-}

+ 18 - 7
app/router/rules/router.go

@@ -41,23 +41,34 @@ func (this *cacheEntry) Extend() {
 }
 
 type Router struct {
-	config *RouterRuleConfig
-	cache  *collect.ValidityMap
-	space  app.Space
+	config    *RouterRuleConfig
+	cache     *collect.ValidityMap
+	dnsServer dns.Server
 }
 
 func NewRouter(config *RouterRuleConfig, space app.Space) *Router {
-	return &Router{
+	r := &Router{
 		config: config,
 		cache:  collect.NewValidityMap(3600),
-		space:  space,
 	}
+	space.InitializeApplication(func() error {
+		if !space.HasApp(dns.APP_ID) {
+			log.Error("DNS: Router is not found in the space.")
+			return app.ErrorMissingApplication
+		}
+		r.dnsServer = space.GetApp(dns.APP_ID).(dns.Server)
+		return nil
+	})
+	return r
+}
+
+func (this *Router) Release() {
+
 }
 
 // @Private
 func (this *Router) ResolveIP(dest v2net.Destination) []v2net.Destination {
-	dnsServer := this.space.GetApp(dns.APP_ID).(dns.Server)
-	ips := dnsServer.Get(dest.Address().Domain())
+	ips := this.dnsServer.Get(dest.Address().Domain())
 	if len(ips) == 0 {
 		return nil
 	}

+ 14 - 2
app/router/rules/router_test.go

@@ -3,6 +3,12 @@ package rules_test
 import (
 	"testing"
 
+	"github.com/v2ray/v2ray-core/app"
+	"github.com/v2ray/v2ray-core/app/dispatcher"
+	dispatchers "github.com/v2ray/v2ray-core/app/dispatcher/impl"
+	"github.com/v2ray/v2ray-core/app/dns"
+	"github.com/v2ray/v2ray-core/app/proxyman"
+	"github.com/v2ray/v2ray-core/app/router"
 	. "github.com/v2ray/v2ray-core/app/router/rules"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	v2testing "github.com/v2ray/v2ray-core/testing"
@@ -21,9 +27,15 @@ func TestSimpleRouter(t *testing.T) {
 		},
 	}
 
-	router := NewRouter(config, nil)
+	space := app.NewSpace()
+	space.BindApp(dns.APP_ID, dns.NewCacheServer(space, &dns.Config{}))
+	space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
+	space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, proxyman.NewDefaultOutboundHandlerManager())
+	r := NewRouter(config, space)
+	space.BindApp(router.APP_ID, r)
+	assert.Error(space.Initialize()).IsNil()
 
-	tag, err := router.TakeDetour(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80))
+	tag, err := r.TakeDetour(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80))
 	assert.Error(err).IsNil()
 	assert.StringLiteral(tag).Equals("test")
 }

+ 56 - 7
app/space.go

@@ -1,5 +1,16 @@
 package app
 
+import (
+	"errors"
+	"sync/atomic"
+
+	"github.com/v2ray/v2ray-core/common"
+)
+
+var (
+	ErrorMissingApplication = errors.New("App: Failed to found one or more applications.")
+)
+
 type ID int
 
 // Context of a function call from proxy to app.
@@ -11,22 +22,60 @@ type Caller interface {
 	Tag() string
 }
 
+type Application interface {
+	common.Releasable
+}
+
+type ApplicationInitializer func() error
+
 // A Space contains all apps that may be available in a V2Ray runtime.
 // Caller must check the availability of an app by calling HasXXX before getting its instance.
 type Space interface {
+	Initialize() error
+	InitializeApplication(ApplicationInitializer)
+
 	HasApp(ID) bool
-	GetApp(ID) interface{}
-	BindApp(ID, interface{})
+	GetApp(ID) Application
+	BindApp(ID, Application)
 }
 
 type spaceImpl struct {
-	cache map[ID]interface{}
+	cache      map[ID]Application
+	initSignal chan struct{}
+	initErrors chan error
+	appsToInit int32
+	appsDone   int32
 }
 
 func NewSpace() Space {
 	return &spaceImpl{
-		cache: make(map[ID]interface{}),
+		cache:      make(map[ID]Application),
+		initSignal: make(chan struct{}),
+		initErrors: make(chan error, 1),
+	}
+}
+
+func (this *spaceImpl) InitializeApplication(f ApplicationInitializer) {
+	atomic.AddInt32(&(this.appsToInit), 1)
+	go func() {
+		<-this.initSignal
+		err := f()
+		if err != nil {
+			this.initErrors <- err
+		}
+		count := atomic.AddInt32(&(this.appsDone), 1)
+		if count == this.appsToInit {
+			close(this.initErrors)
+		}
+	}()
+}
+
+func (this *spaceImpl) Initialize() error {
+	close(this.initSignal)
+	if err, open := <-this.initErrors; open {
+		return err
 	}
+	return nil
 }
 
 func (this *spaceImpl) HasApp(id ID) bool {
@@ -34,7 +83,7 @@ func (this *spaceImpl) HasApp(id ID) bool {
 	return found
 }
 
-func (this *spaceImpl) GetApp(id ID) interface{} {
+func (this *spaceImpl) GetApp(id ID) Application {
 	obj, found := this.cache[id]
 	if !found {
 		return nil
@@ -42,6 +91,6 @@ func (this *spaceImpl) GetApp(id ID) interface{} {
 	return obj
 }
 
-func (this *spaceImpl) BindApp(id ID, object interface{}) {
-	this.cache[id] = object
+func (this *spaceImpl) BindApp(id ID, application Application) {
+	this.cache[id] = application
 }

+ 22 - 0
proxy/socks/server_test.go

@@ -10,6 +10,8 @@ import (
 	"golang.org/x/net/proxy"
 
 	"github.com/v2ray/v2ray-core/app"
+	"github.com/v2ray/v2ray-core/app/dns"
+	v2net "github.com/v2ray/v2ray-core/common/net"
 	v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
 	v2proxy "github.com/v2ray/v2ray-core/proxy"
 	proxytesting "github.com/v2ray/v2ray-core/proxy/testing"
@@ -44,6 +46,11 @@ func TestSocksTcpConnect(t *testing.T) {
         "auth": "noauth"
       }`),
 		},
+		DNSConfig: &dns.Config{
+			NameServers: []v2net.Destination{
+				v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
+			},
+		},
 		OutboundConfig: &point.ConnectionConfig{
 			Protocol: protocol,
 			Settings: nil,
@@ -106,6 +113,11 @@ func TestSocksTcpConnectWithUserPass(t *testing.T) {
         ]
       }`),
 		},
+		DNSConfig: &dns.Config{
+			NameServers: []v2net.Destination{
+				v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
+			},
+		},
 		OutboundConfig: &point.ConnectionConfig{
 			Protocol: protocol,
 			Settings: nil,
@@ -168,6 +180,11 @@ func TestSocksTcpConnectWithWrongUserPass(t *testing.T) {
         ]
       }`),
 		},
+		DNSConfig: &dns.Config{
+			NameServers: []v2net.Destination{
+				v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
+			},
+		},
 		OutboundConfig: &point.ConnectionConfig{
 			Protocol: protocol,
 			Settings: nil,
@@ -216,6 +233,11 @@ func TestSocksTcpConnectWithWrongAuthMethod(t *testing.T) {
         ]
       }`),
 		},
+		DNSConfig: &dns.Config{
+			NameServers: []v2net.Destination{
+				v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
+			},
+		},
 		OutboundConfig: &point.ConnectionConfig{
 			Protocol: protocol,
 			Settings: nil,

+ 11 - 0
proxy/vmess/vmess_test.go

@@ -6,6 +6,7 @@ import (
 
 	"github.com/v2ray/v2ray-core/app"
 	"github.com/v2ray/v2ray-core/app/dispatcher"
+	"github.com/v2ray/v2ray-core/app/dns"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
 	"github.com/v2ray/v2ray-core/common/protocol"
@@ -46,6 +47,11 @@ func TestVMessInAndOut(t *testing.T) {
 
 	configA := &point.Config{
 		Port: portA,
+		DNSConfig: &dns.Config{
+			NameServers: []v2net.Destination{
+				v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
+			},
+		},
 		InboundConfig: &point.ConnectionConfig{
 			Protocol: protocol,
 			Settings: nil,
@@ -86,6 +92,11 @@ func TestVMessInAndOut(t *testing.T) {
 
 	configB := &point.Config{
 		Port: portB,
+		DNSConfig: &dns.Config{
+			NameServers: []v2net.Destination{
+				v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
+			},
+		},
 		InboundConfig: &point.ConnectionConfig{
 			Protocol: "vmess",
 			Settings: []byte(`{

+ 9 - 1
shell/point/point.go

@@ -58,7 +58,7 @@ func NewPoint(pConfig *Config) (*Point, error) {
 	vpoint.space = app.NewSpace()
 	vpoint.space.BindApp(proxyman.APP_ID_INBOUND_MANAGER, vpoint)
 
-	outboundHandlerManager := &proxyman.DefaultOutboundHandlerManager{}
+	outboundHandlerManager := proxyman.NewDefaultOutboundHandlerManager()
 	vpoint.space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager)
 
 	dnsConfig := pConfig.DNSConfig
@@ -144,6 +144,10 @@ func NewPoint(pConfig *Config) (*Point, error) {
 		}
 	}
 
+	if err := vpoint.space.Initialize(); err != nil {
+		return nil, err
+	}
+
 	return vpoint, nil
 }
 
@@ -192,3 +196,7 @@ func (this *Point) GetHandler(tag string) (proxy.InboundHandler, int) {
 	}
 	return handler.GetConnectionHandler()
 }
+
+func (this *Point) Release() {
+
+}