initializable apps

This commit is contained in:
v2ray 2016-05-18 08:12:04 -07:00
parent 7765fedd78
commit 3ded18a75b
12 changed files with 188 additions and 65 deletions

View File

@ -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 {

View File

@ -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()

View File

@ -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}))

View File

@ -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()

View File

@ -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)
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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,

View File

@ -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(`{

View File

@ -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() {
}