mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-01-13 04:46:40 -05:00
initializable apps
This commit is contained in:
parent
7765fedd78
commit
3ded18a75b
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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}))
|
||||
|
@ -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,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)
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
63
app/space.go
63
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,30 +22,68 @@ 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 {
|
||||
_, found := this.cache[id]
|
||||
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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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(`{
|
||||
|
@ -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() {
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user