Prechádzať zdrojové kódy

protobuf for v2ray config

Darien Raymond 9 rokov pred
rodič
commit
0a32345af9
9 zmenil súbory, kde vykonal 479 pridanie a 536 odobranie
  1. 18 57
      config.go
  2. 318 0
      config.pb.go
  3. 61 0
      config.proto
  4. 0 246
      config_json.go
  5. 0 81
      config_json_test.go
  6. 8 5
      inbound_detour_always.go
  7. 8 8
      inbound_detour_dynamic.go
  8. 4 19
      proxy/registry/handler_cache.go
  9. 62 120
      v2ray.go

+ 18 - 57
config.go

@@ -3,72 +3,33 @@ package core
 import (
 	"io"
 
-	"v2ray.com/core/app/dns"
-	"v2ray.com/core/app/router"
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/log"
-	v2net "v2ray.com/core/common/net"
-	"v2ray.com/core/transport"
-	"v2ray.com/core/transport/internet"
+	"v2ray.com/core/proxy/registry"
 )
 
-type InboundConnectionConfig struct {
-	Port                   v2net.Port
-	ListenOn               v2net.Address
-	StreamSettings         *internet.StreamConfig
-	Protocol               string
-	Settings               []byte
-	AllowPassiveConnection bool
-}
-
-type OutboundConnectionConfig struct {
-	Protocol       string
-	SendThrough    v2net.Address
-	StreamSettings *internet.StreamConfig
-	Settings       []byte
-}
-
-const (
-	AllocationStrategyAlways   = "always"
-	AllocationStrategyRandom   = "random"
-	AllocationStrategyExternal = "external"
-)
-
-type InboundDetourAllocationConfig struct {
-	Strategy    string // Allocation strategy of this inbound detour.
-	Concurrency int    // Number of handlers (ports) running in parallel.
-	Refresh     int    // Number of minutes before a handler is regenerated.
+func (this *AllocationStrategyConcurrency) GetValue() uint32 {
+	if this == nil {
+		return 3
+	}
+	return this.Value
 }
 
-type InboundDetourConfig struct {
-	Protocol               string
-	PortRange              v2net.PortRange
-	ListenOn               v2net.Address
-	Tag                    string
-	Allocation             *InboundDetourAllocationConfig
-	StreamSettings         *internet.StreamConfig
-	Settings               []byte
-	AllowPassiveConnection bool
+func (this *AllocationStrategyRefresh) GetValue() uint32 {
+	if this == nil {
+		return 5
+	}
+	return this.Value
 }
 
-type OutboundDetourConfig struct {
-	Protocol       string
-	SendThrough    v2net.Address
-	StreamSettings *internet.StreamConfig
-	Tag            string
-	Settings       []byte
+func (this *InboundConnectionConfig) GetAllocationStrategyValue() *AllocationStrategy {
+	if this.AllocationStrategy == nil {
+		return &AllocationStrategy{}
+	}
+	return this.AllocationStrategy
 }
 
-type Config struct {
-	Port            v2net.Port
-	LogConfig       *log.Config
-	RouterConfig    *router.Config
-	DNSConfig       *dns.Config
-	InboundConfig   *InboundConnectionConfig
-	OutboundConfig  *OutboundConnectionConfig
-	InboundDetours  []*InboundDetourConfig
-	OutboundDetours []*OutboundDetourConfig
-	TransportConfig *transport.Config
+func (this *InboundConnectionConfig) GetTypedSettings() (interface{}, error) {
+	return registry.MarshalInboundConfig(this.Protocol, this.Settings)
 }
 
 type ConfigLoader func(input io.Reader) (*Config, error)

+ 318 - 0
config.pb.go

@@ -0,0 +1,318 @@
+// Code generated by protoc-gen-go.
+// source: v2ray.com/core/config.proto
+// DO NOT EDIT!
+
+/*
+Package core is a generated protocol buffer package.
+
+It is generated from these files:
+	v2ray.com/core/config.proto
+
+It has these top-level messages:
+	AllocationStrategyConcurrency
+	AllocationStrategyRefresh
+	AllocationStrategy
+	InboundConnectionConfig
+	OutboundConnectionConfig
+	Config
+*/
+package core
+
+import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+import v2ray_core_app_router "v2ray.com/core/app/router"
+import v2ray_core_app_dns "v2ray.com/core/app/dns"
+import v2ray_core_common_net "v2ray.com/core/common/net"
+import v2ray_core_common_net2 "v2ray.com/core/common/net"
+import v2ray_core_common_log "v2ray.com/core/common/log"
+import v2ray_core_transport_internet "v2ray.com/core/transport/internet"
+import v2ray_core_transport "v2ray.com/core/transport"
+import google_protobuf "github.com/golang/protobuf/ptypes/any"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type AllocationStrategy_Type int32
+
+const (
+	// Always allocate all connection handlers.
+	AllocationStrategy_Always AllocationStrategy_Type = 0
+	// Randomly allocate specific range of handlers.
+	AllocationStrategy_Random AllocationStrategy_Type = 1
+	// External. Not supported yet.
+	AllocationStrategy_External AllocationStrategy_Type = 2
+)
+
+var AllocationStrategy_Type_name = map[int32]string{
+	0: "Always",
+	1: "Random",
+	2: "External",
+}
+var AllocationStrategy_Type_value = map[string]int32{
+	"Always":   0,
+	"Random":   1,
+	"External": 2,
+}
+
+func (x AllocationStrategy_Type) String() string {
+	return proto.EnumName(AllocationStrategy_Type_name, int32(x))
+}
+func (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} }
+
+type AllocationStrategyConcurrency struct {
+	Value uint32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
+}
+
+func (m *AllocationStrategyConcurrency) Reset()                    { *m = AllocationStrategyConcurrency{} }
+func (m *AllocationStrategyConcurrency) String() string            { return proto.CompactTextString(m) }
+func (*AllocationStrategyConcurrency) ProtoMessage()               {}
+func (*AllocationStrategyConcurrency) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+type AllocationStrategyRefresh struct {
+	Value uint32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
+}
+
+func (m *AllocationStrategyRefresh) Reset()                    { *m = AllocationStrategyRefresh{} }
+func (m *AllocationStrategyRefresh) String() string            { return proto.CompactTextString(m) }
+func (*AllocationStrategyRefresh) ProtoMessage()               {}
+func (*AllocationStrategyRefresh) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+type AllocationStrategy struct {
+	Type AllocationStrategy_Type `protobuf:"varint,1,opt,name=type,enum=v2ray.core.AllocationStrategy_Type" json:"type,omitempty"`
+	// Number of handlers (ports) running in parallel.
+	Concurrency *AllocationStrategyConcurrency `protobuf:"bytes,2,opt,name=concurrency" json:"concurrency,omitempty"`
+	// Number of minutes before a handler is regenerated.
+	Refresh *AllocationStrategyRefresh `protobuf:"bytes,3,opt,name=refresh" json:"refresh,omitempty"`
+}
+
+func (m *AllocationStrategy) Reset()                    { *m = AllocationStrategy{} }
+func (m *AllocationStrategy) String() string            { return proto.CompactTextString(m) }
+func (*AllocationStrategy) ProtoMessage()               {}
+func (*AllocationStrategy) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
+
+func (m *AllocationStrategy) GetConcurrency() *AllocationStrategyConcurrency {
+	if m != nil {
+		return m.Concurrency
+	}
+	return nil
+}
+
+func (m *AllocationStrategy) GetRefresh() *AllocationStrategyRefresh {
+	if m != nil {
+		return m.Refresh
+	}
+	return nil
+}
+
+// Config for an inbound connection handler.
+type InboundConnectionConfig struct {
+	Protocol               string                                      `protobuf:"bytes,1,opt,name=protocol" json:"protocol,omitempty"`
+	PortRange              *v2ray_core_common_net.PortRange            `protobuf:"bytes,2,opt,name=port_range,json=portRange" json:"port_range,omitempty"`
+	ListenOn               *v2ray_core_common_net2.IPOrDomain          `protobuf:"bytes,3,opt,name=listen_on,json=listenOn" json:"listen_on,omitempty"`
+	Tag                    string                                      `protobuf:"bytes,4,opt,name=tag" json:"tag,omitempty"`
+	AllocationStrategy     *AllocationStrategy                         `protobuf:"bytes,5,opt,name=allocation_strategy,json=allocationStrategy" json:"allocation_strategy,omitempty"`
+	StreamSettings         *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,6,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
+	Settings               *google_protobuf.Any                        `protobuf:"bytes,7,opt,name=settings" json:"settings,omitempty"`
+	AllowPassiveConnection bool                                        `protobuf:"varint,8,opt,name=allow_passive_connection,json=allowPassiveConnection" json:"allow_passive_connection,omitempty"`
+}
+
+func (m *InboundConnectionConfig) Reset()                    { *m = InboundConnectionConfig{} }
+func (m *InboundConnectionConfig) String() string            { return proto.CompactTextString(m) }
+func (*InboundConnectionConfig) ProtoMessage()               {}
+func (*InboundConnectionConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
+
+func (m *InboundConnectionConfig) GetPortRange() *v2ray_core_common_net.PortRange {
+	if m != nil {
+		return m.PortRange
+	}
+	return nil
+}
+
+func (m *InboundConnectionConfig) GetListenOn() *v2ray_core_common_net2.IPOrDomain {
+	if m != nil {
+		return m.ListenOn
+	}
+	return nil
+}
+
+func (m *InboundConnectionConfig) GetAllocationStrategy() *AllocationStrategy {
+	if m != nil {
+		return m.AllocationStrategy
+	}
+	return nil
+}
+
+func (m *InboundConnectionConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
+	if m != nil {
+		return m.StreamSettings
+	}
+	return nil
+}
+
+func (m *InboundConnectionConfig) GetSettings() *google_protobuf.Any {
+	if m != nil {
+		return m.Settings
+	}
+	return nil
+}
+
+type OutboundConnectionConfig struct {
+	Protocol       string                                      `protobuf:"bytes,1,opt,name=protocol" json:"protocol,omitempty"`
+	SendThrough    *v2ray_core_common_net2.IPOrDomain          `protobuf:"bytes,2,opt,name=send_through,json=sendThrough" json:"send_through,omitempty"`
+	StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,3,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
+	Tag            string                                      `protobuf:"bytes,4,opt,name=tag" json:"tag,omitempty"`
+	Settings       *google_protobuf.Any                        `protobuf:"bytes,5,opt,name=settings" json:"settings,omitempty"`
+}
+
+func (m *OutboundConnectionConfig) Reset()                    { *m = OutboundConnectionConfig{} }
+func (m *OutboundConnectionConfig) String() string            { return proto.CompactTextString(m) }
+func (*OutboundConnectionConfig) ProtoMessage()               {}
+func (*OutboundConnectionConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
+
+func (m *OutboundConnectionConfig) GetSendThrough() *v2ray_core_common_net2.IPOrDomain {
+	if m != nil {
+		return m.SendThrough
+	}
+	return nil
+}
+
+func (m *OutboundConnectionConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
+	if m != nil {
+		return m.StreamSettings
+	}
+	return nil
+}
+
+func (m *OutboundConnectionConfig) GetSettings() *google_protobuf.Any {
+	if m != nil {
+		return m.Settings
+	}
+	return nil
+}
+
+type Config struct {
+	Inbound   []*InboundConnectionConfig    `protobuf:"bytes,1,rep,name=inbound" json:"inbound,omitempty"`
+	Outbound  []*OutboundConnectionConfig   `protobuf:"bytes,2,rep,name=outbound" json:"outbound,omitempty"`
+	Log       *v2ray_core_common_log.Config `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"`
+	Router    *v2ray_core_app_router.Config `protobuf:"bytes,4,opt,name=router" json:"router,omitempty"`
+	Dns       *v2ray_core_app_dns.Config    `protobuf:"bytes,5,opt,name=dns" json:"dns,omitempty"`
+	Transport *v2ray_core_transport.Config  `protobuf:"bytes,6,opt,name=transport" json:"transport,omitempty"`
+}
+
+func (m *Config) Reset()                    { *m = Config{} }
+func (m *Config) String() string            { return proto.CompactTextString(m) }
+func (*Config) ProtoMessage()               {}
+func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
+
+func (m *Config) GetInbound() []*InboundConnectionConfig {
+	if m != nil {
+		return m.Inbound
+	}
+	return nil
+}
+
+func (m *Config) GetOutbound() []*OutboundConnectionConfig {
+	if m != nil {
+		return m.Outbound
+	}
+	return nil
+}
+
+func (m *Config) GetLog() *v2ray_core_common_log.Config {
+	if m != nil {
+		return m.Log
+	}
+	return nil
+}
+
+func (m *Config) GetRouter() *v2ray_core_app_router.Config {
+	if m != nil {
+		return m.Router
+	}
+	return nil
+}
+
+func (m *Config) GetDns() *v2ray_core_app_dns.Config {
+	if m != nil {
+		return m.Dns
+	}
+	return nil
+}
+
+func (m *Config) GetTransport() *v2ray_core_transport.Config {
+	if m != nil {
+		return m.Transport
+	}
+	return nil
+}
+
+func init() {
+	proto.RegisterType((*AllocationStrategyConcurrency)(nil), "v2ray.core.AllocationStrategyConcurrency")
+	proto.RegisterType((*AllocationStrategyRefresh)(nil), "v2ray.core.AllocationStrategyRefresh")
+	proto.RegisterType((*AllocationStrategy)(nil), "v2ray.core.AllocationStrategy")
+	proto.RegisterType((*InboundConnectionConfig)(nil), "v2ray.core.InboundConnectionConfig")
+	proto.RegisterType((*OutboundConnectionConfig)(nil), "v2ray.core.OutboundConnectionConfig")
+	proto.RegisterType((*Config)(nil), "v2ray.core.Config")
+	proto.RegisterEnum("v2ray.core.AllocationStrategy_Type", AllocationStrategy_Type_name, AllocationStrategy_Type_value)
+}
+
+func init() { proto.RegisterFile("v2ray.com/core/config.proto", fileDescriptor0) }
+
+var fileDescriptor0 = []byte{
+	// 723 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x95, 0xdb, 0x6e, 0xd3, 0x30,
+	0x18, 0xc7, 0xe9, 0x61, 0x5d, 0xfb, 0x75, 0x8c, 0xca, 0x4c, 0x90, 0x15, 0x86, 0x4a, 0x77, 0xa0,
+	0x88, 0x29, 0x81, 0xa1, 0x09, 0x84, 0x04, 0x63, 0x07, 0x2e, 0x26, 0x2e, 0x5a, 0x65, 0xbb, 0xe2,
+	0xa6, 0xf2, 0x12, 0x2f, 0x8b, 0x94, 0xda, 0x91, 0xed, 0x6e, 0xe4, 0x11, 0x78, 0x01, 0x5e, 0x6e,
+	0x2f, 0x83, 0x62, 0x3b, 0xe9, 0x79, 0x0c, 0x71, 0x17, 0xd7, 0xff, 0xdf, 0xe7, 0xcf, 0xff, 0xbf,
+	0x3f, 0x15, 0x9e, 0x5d, 0xef, 0x71, 0x9c, 0xd8, 0x1e, 0x1b, 0x38, 0x1e, 0xe3, 0xc4, 0xf1, 0x18,
+	0xbd, 0x0c, 0x03, 0x3b, 0xe6, 0x4c, 0x32, 0x04, 0xd9, 0x26, 0x27, 0xcd, 0x9d, 0x29, 0x21, 0x8e,
+	0x63, 0x87, 0xb3, 0xa1, 0x24, 0x7c, 0x82, 0x69, 0x6e, 0xce, 0xd1, 0xf9, 0x54, 0x4c, 0x8a, 0xb6,
+	0x66, 0x4e, 0x1d, 0x0c, 0x18, 0x75, 0x28, 0x91, 0x4e, 0xcc, 0xb8, 0x34, 0xaa, 0x57, 0x8b, 0x55,
+	0xd8, 0xf7, 0x39, 0x11, 0xc2, 0x08, 0x77, 0xe6, 0x0b, 0x23, 0x16, 0x4c, 0x1e, 0x6b, 0x4f, 0xe9,
+	0x24, 0xc7, 0x54, 0xa4, 0x07, 0x3a, 0x21, 0x95, 0x84, 0xa7, 0x85, 0x27, 0xf4, 0xdb, 0x0b, 0xf5,
+	0x13, 0xb2, 0xf5, 0x80, 0xb1, 0x20, 0x22, 0x8e, 0x5a, 0x5d, 0x0c, 0x2f, 0x1d, 0x4c, 0x13, 0xbd,
+	0xd5, 0xde, 0x87, 0x8d, 0xc3, 0x28, 0x62, 0x1e, 0x96, 0x21, 0xa3, 0x67, 0x92, 0x63, 0x49, 0x82,
+	0xe4, 0x98, 0x51, 0x6f, 0xc8, 0x39, 0xa1, 0x5e, 0x82, 0xd6, 0x60, 0xe9, 0x1a, 0x47, 0x43, 0x62,
+	0x15, 0x5a, 0x85, 0xce, 0x43, 0x57, 0x2f, 0xda, 0xef, 0x60, 0x7d, 0x16, 0x73, 0xc9, 0x25, 0x27,
+	0xe2, 0x6a, 0x01, 0xf2, 0xab, 0x08, 0x68, 0x96, 0x41, 0x1f, 0xa0, 0x2c, 0x93, 0x58, 0x6b, 0x57,
+	0xf7, 0x36, 0xed, 0x51, 0xa2, 0xf6, 0xac, 0xda, 0x3e, 0x4f, 0x62, 0xe2, 0x2a, 0x00, 0x7d, 0x87,
+	0xba, 0x37, 0xea, 0xd3, 0x2a, 0xb6, 0x0a, 0x9d, 0xfa, 0xde, 0xeb, 0xbb, 0xf9, 0xb1, 0x8b, 0xb9,
+	0xe3, 0x34, 0x3a, 0x80, 0x65, 0xae, 0xbb, 0xb7, 0x4a, 0xaa, 0xd0, 0xf6, 0xdd, 0x85, 0xcc, 0x55,
+	0xdd, 0x8c, 0x6a, 0xef, 0x42, 0x39, 0xed, 0x0d, 0x01, 0x54, 0x0e, 0xa3, 0x1b, 0x9c, 0x88, 0xc6,
+	0x83, 0xf4, 0xdb, 0xc5, 0xd4, 0x67, 0x83, 0x46, 0x01, 0xad, 0x40, 0xf5, 0xdb, 0xcf, 0x34, 0x42,
+	0x1c, 0x35, 0x8a, 0xed, 0xdb, 0x12, 0x3c, 0x3d, 0xa5, 0x17, 0x6c, 0x48, 0xfd, 0x63, 0x46, 0x29,
+	0xf1, 0xd2, 0xda, 0xc7, 0x2a, 0x32, 0xd4, 0x84, 0xaa, 0x8a, 0xc6, 0x63, 0x91, 0x32, 0xa5, 0xe6,
+	0xe6, 0x6b, 0x74, 0x00, 0x90, 0xa6, 0xdb, 0xe7, 0x98, 0x06, 0xc4, 0x5c, 0xb9, 0x35, 0xde, 0xa9,
+	0x7e, 0x58, 0x36, 0x25, 0xd2, 0xee, 0x31, 0x2e, 0xdd, 0x54, 0xe7, 0xd6, 0xe2, 0xec, 0x13, 0x7d,
+	0x81, 0x5a, 0x14, 0x0a, 0x49, 0x68, 0x9f, 0x51, 0x73, 0xd3, 0x97, 0x0b, 0xf8, 0xd3, 0x5e, 0x97,
+	0x9f, 0xb0, 0x01, 0x0e, 0xa9, 0x5b, 0xd5, 0x4c, 0x97, 0xa2, 0x06, 0x94, 0x24, 0x0e, 0xac, 0xb2,
+	0xea, 0x2b, 0xfd, 0x44, 0x5d, 0x78, 0x8c, 0x73, 0x7b, 0xfa, 0xc2, 0xf8, 0x63, 0x2d, 0xa9, 0xda,
+	0x2f, 0xfe, 0xe2, 0x22, 0xc2, 0xb3, 0x0f, 0xe2, 0x1c, 0x1e, 0x09, 0xc9, 0x09, 0x1e, 0xf4, 0x05,
+	0x91, 0x32, 0xa4, 0x81, 0xb0, 0x2a, 0xaa, 0xd8, 0x9b, 0xf1, 0x62, 0xf9, 0x4b, 0xb7, 0xb3, 0xc9,
+	0xb0, 0xcf, 0x14, 0xa5, 0x5d, 0x74, 0x57, 0x75, 0x8d, 0x33, 0x53, 0x02, 0xbd, 0x85, 0x6a, 0x5e,
+	0x6e, 0x59, 0x95, 0x5b, 0xb3, 0xf5, 0x54, 0xd8, 0xd9, 0x54, 0xd8, 0x87, 0x34, 0x71, 0x73, 0x15,
+	0xfa, 0x08, 0x56, 0xda, 0xdd, 0x4d, 0x3f, 0xc6, 0x42, 0x84, 0xd7, 0xa4, 0xef, 0xe5, 0x49, 0x59,
+	0xd5, 0x56, 0xa1, 0x53, 0x75, 0x9f, 0xa8, 0xfd, 0x9e, 0xde, 0x1e, 0xe5, 0xd8, 0xfe, 0x5d, 0x04,
+	0xab, 0x3b, 0x94, 0xff, 0x1e, 0xef, 0x09, 0xac, 0x08, 0x42, 0xfd, 0xbe, 0xbc, 0xe2, 0x6c, 0x18,
+	0x5c, 0x99, 0x80, 0xef, 0x11, 0x50, 0x3d, 0xc5, 0xce, 0x35, 0x35, 0xcf, 0xc0, 0xd2, 0xff, 0x1b,
+	0x38, 0x9b, 0xfc, 0xb8, 0xa5, 0x4b, 0xf7, 0xb1, 0xb4, 0x7d, 0x5b, 0x84, 0x8a, 0xb1, 0xe1, 0x33,
+	0x2c, 0x87, 0x7a, 0x00, 0xac, 0x42, 0xab, 0xd4, 0xa9, 0x4f, 0x4e, 0xfe, 0x82, 0xd9, 0x70, 0x33,
+	0x06, 0x7d, 0x85, 0x2a, 0x33, 0x0e, 0x5b, 0x45, 0xc5, 0x6f, 0x8d, 0xf3, 0x8b, 0xdc, 0x77, 0x73,
+	0x0a, 0x39, 0x50, 0x8a, 0x58, 0x60, 0x9c, 0xd9, 0x98, 0x63, 0x71, 0xc4, 0x02, 0xdb, 0x50, 0xa9,
+	0x12, 0xed, 0x43, 0x45, 0xff, 0x9d, 0x28, 0x0f, 0xa6, 0x18, 0x1c, 0xc7, 0xb6, 0xde, 0xcd, 0x18,
+	0x23, 0x46, 0xbb, 0x50, 0xf2, 0x69, 0x66, 0x50, 0x73, 0x9a, 0xf1, 0xa9, 0xc8, 0x0f, 0xf1, 0xa9,
+	0x40, 0x9f, 0xa0, 0x96, 0x07, 0x63, 0x9e, 0xfd, 0xf3, 0xf9, 0xa9, 0x19, 0x6a, 0x24, 0x3f, 0xda,
+	0x84, 0x55, 0x8f, 0x0d, 0xc6, 0xd4, 0x47, 0x75, 0x2d, 0xea, 0xa5, 0x69, 0xfc, 0x28, 0xa7, 0x3f,
+	0x5d, 0x54, 0x54, 0x34, 0xef, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x05, 0x33, 0xc3, 0x7f, 0x57,
+	0x07, 0x00, 0x00,
+}

+ 61 - 0
config.proto

@@ -5,9 +5,70 @@ option go_package = "core";
 option java_package = "com.v2ray.core";
 option java_outer_classname = "ConfigProto";
 
+import "v2ray.com/core/app/router/config.proto";
+import "v2ray.com/core/app/dns/config.proto";
+import "v2ray.com/core/common/net/port.proto";
+import "v2ray.com/core/common/net/address.proto";
+import "v2ray.com/core/common/log/config.proto";
+import "v2ray.com/core/transport/internet/config.proto";
+import "v2ray.com/core/transport/config.proto";
 
+import "google/protobuf/any.proto";
 
+message AllocationStrategyConcurrency {
+  uint32 value = 1;
+}
+
+message AllocationStrategyRefresh {
+  uint32 value = 1;
+}
+
+message AllocationStrategy {
+  enum Type {
+    // Always allocate all connection handlers.
+    Always = 0;
+
+    // Randomly allocate specific range of handlers.
+    Random = 1;
+
+    // External. Not supported yet.
+    External = 2;
+  }
+
+  Type type = 1;
+
+  // Number of handlers (ports) running in parallel.
+  AllocationStrategyConcurrency concurrency = 2;
+
+  // Number of minutes before a handler is regenerated.
+  AllocationStrategyRefresh refresh = 3;
+}
+
+// Config for an inbound connection handler.
 message InboundConnectionConfig {
   string protocol = 1;
+  v2ray.core.common.net.PortRange port_range = 2;
+  v2ray.core.common.net.IPOrDomain listen_on = 3;
+  string tag = 4;
+  AllocationStrategy allocation_strategy = 5;
+  v2ray.core.transport.internet.StreamConfig stream_settings = 6;
+  google.protobuf.Any settings = 7;
+  bool allow_passive_connection = 8;
+}
+
+message OutboundConnectionConfig {
+  string protocol = 1;
+  v2ray.core.common.net.IPOrDomain send_through = 2;
+  v2ray.core.transport.internet.StreamConfig stream_settings = 3;
+  string tag = 4;
+  google.protobuf.Any settings = 5;
+}
 
+message Config {
+  repeated InboundConnectionConfig inbound = 1;
+  repeated OutboundConnectionConfig outbound = 2;
+  v2ray.core.common.log.Config log = 3;
+  v2ray.core.app.router.Config router = 4;
+  v2ray.core.app.dns.Config dns = 5;
+  v2ray.core.transport.Config transport = 6;
 }

+ 0 - 246
config_json.go

@@ -1,246 +0,0 @@
-// +build json
-
-package core
-
-import (
-	"encoding/json"
-	"errors"
-	"io"
-
-	"v2ray.com/core/app/dns"
-	"v2ray.com/core/app/router"
-	"v2ray.com/core/common"
-	"v2ray.com/core/common/log"
-	v2net "v2ray.com/core/common/net"
-	"v2ray.com/core/transport"
-	"v2ray.com/core/transport/internet"
-)
-
-const (
-	DefaultRefreshMinute = int(9999)
-)
-
-func (this *Config) UnmarshalJSON(data []byte) error {
-	type JsonConfig struct {
-		Port            v2net.Port                `json:"port"` // Port of this Point server.
-		LogConfig       *log.Config               `json:"log"`
-		RouterConfig    *router.Config            `json:"routing"`
-		DNSConfig       *dns.Config               `json:"dns"`
-		InboundConfig   *InboundConnectionConfig  `json:"inbound"`
-		OutboundConfig  *OutboundConnectionConfig `json:"outbound"`
-		InboundDetours  []*InboundDetourConfig    `json:"inboundDetour"`
-		OutboundDetours []*OutboundDetourConfig   `json:"outboundDetour"`
-		Transport       *transport.Config         `json:"transport"`
-	}
-	jsonConfig := new(JsonConfig)
-	if err := json.Unmarshal(data, jsonConfig); err != nil {
-		return errors.New("Point: Failed to parse config: " + err.Error())
-	}
-	this.Port = jsonConfig.Port
-	this.LogConfig = jsonConfig.LogConfig
-	this.RouterConfig = jsonConfig.RouterConfig
-
-	if jsonConfig.InboundConfig == nil {
-		return errors.New("Point: Inbound config is not specified.")
-	}
-	this.InboundConfig = jsonConfig.InboundConfig
-
-	if jsonConfig.OutboundConfig == nil {
-		return errors.New("Point: Outbound config is not specified.")
-	}
-	this.OutboundConfig = jsonConfig.OutboundConfig
-	this.InboundDetours = jsonConfig.InboundDetours
-	this.OutboundDetours = jsonConfig.OutboundDetours
-	if jsonConfig.DNSConfig == nil {
-		jsonConfig.DNSConfig = &dns.Config{
-			NameServers: []*v2net.Endpoint{{
-				Network: v2net.Network_UDP,
-				Address: &v2net.IPOrDomain{
-					Address: &v2net.IPOrDomain_Domain{
-						Domain: "localhost",
-					},
-				},
-				Port: 53,
-			}},
-		}
-	}
-	this.DNSConfig = jsonConfig.DNSConfig
-	this.TransportConfig = jsonConfig.Transport
-	return nil
-}
-
-func (this *InboundConnectionConfig) UnmarshalJSON(data []byte) error {
-	type JsonConfig struct {
-		Port          uint16                 `json:"port"`
-		Listen        *v2net.IPOrDomain      `json:"listen"`
-		Protocol      string                 `json:"protocol"`
-		StreamSetting *internet.StreamConfig `json:"streamSettings"`
-		Settings      json.RawMessage        `json:"settings"`
-		AllowPassive  bool                   `json:"allowPassive"`
-	}
-
-	jsonConfig := new(JsonConfig)
-	if err := json.Unmarshal(data, jsonConfig); err != nil {
-		return errors.New("Point: Failed to parse inbound config: " + err.Error())
-	}
-	this.Port = v2net.Port(jsonConfig.Port)
-	this.ListenOn = v2net.AnyIP
-	if jsonConfig.Listen != nil {
-		if jsonConfig.Listen.AsAddress().Family().IsDomain() {
-			return errors.New("Point: Unable to listen on domain address: " + jsonConfig.Listen.AsAddress().Domain())
-		}
-		this.ListenOn = jsonConfig.Listen.AsAddress()
-	}
-	if jsonConfig.StreamSetting != nil {
-		this.StreamSettings = jsonConfig.StreamSetting
-	}
-
-	this.Protocol = jsonConfig.Protocol
-	this.Settings = jsonConfig.Settings
-	this.AllowPassiveConnection = jsonConfig.AllowPassive
-	return nil
-}
-
-func (this *OutboundConnectionConfig) UnmarshalJSON(data []byte) error {
-	type JsonConnectionConfig struct {
-		Protocol      string                 `json:"protocol"`
-		SendThrough   *v2net.IPOrDomain      `json:"sendThrough"`
-		StreamSetting *internet.StreamConfig `json:"streamSettings"`
-		Settings      json.RawMessage        `json:"settings"`
-	}
-	jsonConfig := new(JsonConnectionConfig)
-	if err := json.Unmarshal(data, jsonConfig); err != nil {
-		return errors.New("Point: Failed to parse outbound config: " + err.Error())
-	}
-	this.Protocol = jsonConfig.Protocol
-	this.Settings = jsonConfig.Settings
-
-	if jsonConfig.SendThrough != nil {
-		address := jsonConfig.SendThrough.AsAddress()
-		if address.Family().IsDomain() {
-			return errors.New("Point: Unable to send through: " + address.String())
-		}
-		this.SendThrough = address
-	}
-	if jsonConfig.StreamSetting != nil {
-		this.StreamSettings = jsonConfig.StreamSetting
-	}
-	return nil
-}
-
-func (this *InboundDetourAllocationConfig) UnmarshalJSON(data []byte) error {
-	type JsonInboundDetourAllocationConfig struct {
-		Strategy    string `json:"strategy"`
-		Concurrency int    `json:"concurrency"`
-		RefreshMin  int    `json:"refresh"`
-	}
-	jsonConfig := new(JsonInboundDetourAllocationConfig)
-	if err := json.Unmarshal(data, jsonConfig); err != nil {
-		return errors.New("Point: Failed to parse inbound detour allocation config: " + err.Error())
-	}
-	this.Strategy = jsonConfig.Strategy
-	this.Concurrency = jsonConfig.Concurrency
-	this.Refresh = jsonConfig.RefreshMin
-	if this.Strategy == AllocationStrategyRandom {
-		if this.Refresh == 0 {
-			this.Refresh = 5
-		}
-		if this.Concurrency == 0 {
-			this.Concurrency = 3
-		}
-	}
-	if this.Refresh == 0 {
-		this.Refresh = DefaultRefreshMinute
-	}
-	return nil
-}
-
-func (this *InboundDetourConfig) UnmarshalJSON(data []byte) error {
-	type JsonInboundDetourConfig struct {
-		Protocol      string                         `json:"protocol"`
-		PortRange     *v2net.PortRange               `json:"port"`
-		ListenOn      *v2net.IPOrDomain              `json:"listen"`
-		Settings      json.RawMessage                `json:"settings"`
-		Tag           string                         `json:"tag"`
-		Allocation    *InboundDetourAllocationConfig `json:"allocate"`
-		StreamSetting *internet.StreamConfig         `json:"streamSettings"`
-		AllowPassive  bool                           `json:"allowPassive"`
-	}
-	jsonConfig := new(JsonInboundDetourConfig)
-	if err := json.Unmarshal(data, jsonConfig); err != nil {
-		return errors.New("Point: Failed to parse inbound detour config: " + err.Error())
-	}
-	if jsonConfig.PortRange == nil {
-		log.Error("Point: Port range not specified in InboundDetour.")
-		return common.ErrBadConfiguration
-	}
-	this.ListenOn = v2net.AnyIP
-	if jsonConfig.ListenOn != nil {
-		if jsonConfig.ListenOn.AsAddress().Family().IsDomain() {
-			return errors.New("Point: Unable to listen on domain address: " + jsonConfig.ListenOn.AsAddress().Domain())
-		}
-		this.ListenOn = jsonConfig.ListenOn.AsAddress()
-	}
-	this.Protocol = jsonConfig.Protocol
-	this.PortRange = *jsonConfig.PortRange
-	this.Settings = jsonConfig.Settings
-	this.Tag = jsonConfig.Tag
-	this.Allocation = jsonConfig.Allocation
-	if this.Allocation == nil {
-		this.Allocation = &InboundDetourAllocationConfig{
-			Strategy: AllocationStrategyAlways,
-			Refresh:  DefaultRefreshMinute,
-		}
-	}
-	if jsonConfig.StreamSetting != nil {
-		this.StreamSettings = jsonConfig.StreamSetting
-	}
-	this.AllowPassiveConnection = jsonConfig.AllowPassive
-	return nil
-}
-
-func (this *OutboundDetourConfig) UnmarshalJSON(data []byte) error {
-	type JsonOutboundDetourConfig struct {
-		Protocol      string                 `json:"protocol"`
-		SendThrough   *v2net.IPOrDomain      `json:"sendThrough"`
-		Tag           string                 `json:"tag"`
-		Settings      json.RawMessage        `json:"settings"`
-		StreamSetting *internet.StreamConfig `json:"streamSettings"`
-	}
-	jsonConfig := new(JsonOutboundDetourConfig)
-	if err := json.Unmarshal(data, jsonConfig); err != nil {
-		return errors.New("Point: Failed to parse outbound detour config: " + err.Error())
-	}
-	this.Protocol = jsonConfig.Protocol
-	this.Tag = jsonConfig.Tag
-	this.Settings = jsonConfig.Settings
-
-	if jsonConfig.SendThrough != nil {
-		address := jsonConfig.SendThrough.AsAddress()
-		if address.Family().IsDomain() {
-			return errors.New("Point: Unable to send through: " + address.String())
-		}
-		this.SendThrough = address
-	}
-
-	if jsonConfig.StreamSetting != nil {
-		this.StreamSettings = jsonConfig.StreamSetting
-	}
-	return nil
-}
-
-func JsonLoadConfig(input io.Reader) (*Config, error) {
-	jsonConfig := &Config{}
-	decoder := json.NewDecoder(input)
-	err := decoder.Decode(jsonConfig)
-	if err != nil {
-		log.Error("Point: Failed to load server config: ", err)
-		return nil, err
-	}
-
-	return jsonConfig, err
-}
-
-func init() {
-	configLoader = JsonLoadConfig
-}

+ 0 - 81
config_json_test.go

@@ -1,81 +0,0 @@
-// +build json
-
-package core_test
-
-import (
-	"encoding/json"
-	"io"
-	"os"
-	"path/filepath"
-	"testing"
-
-	. "v2ray.com/core"
-
-	"v2ray.com/core/testing/assert"
-)
-
-func OpenFile(file string, assert *assert.Assert) io.Reader {
-	input, err := os.Open(file)
-	assert.Error(err).IsNil()
-	return input
-}
-
-func TestClientSampleConfig(t *testing.T) {
-	assert := assert.On(t)
-
-	GOPATH := os.Getenv("GOPATH")
-	baseDir := filepath.Join(GOPATH, "src", "v2ray.com", "core", "tools", "release", "config")
-
-	pointConfig, err := LoadConfig(OpenFile(filepath.Join(baseDir, "vpoint_socks_vmess.json"), assert))
-	assert.Error(err).IsNil()
-
-	assert.Pointer(pointConfig.InboundConfig).IsNotNil()
-	assert.Port(pointConfig.InboundConfig.Port).IsValid()
-	assert.Pointer(pointConfig.OutboundConfig).IsNotNil()
-
-	assert.String(pointConfig.InboundConfig.Protocol).Equals("socks")
-	assert.Pointer(pointConfig.InboundConfig.Settings).IsNotNil()
-
-	assert.String(pointConfig.OutboundConfig.Protocol).Equals("vmess")
-	assert.Pointer(pointConfig.OutboundConfig.Settings).IsNotNil()
-}
-
-func TestServerSampleConfig(t *testing.T) {
-	assert := assert.On(t)
-
-	GOPATH := os.Getenv("GOPATH")
-	baseDir := filepath.Join(GOPATH, "src", "v2ray.com", "core", "tools", "release", "config")
-
-	pointConfig, err := LoadConfig(OpenFile(filepath.Join(baseDir, "vpoint_vmess_freedom.json"), assert))
-	assert.Error(err).IsNil()
-
-	assert.Pointer(pointConfig.InboundConfig).IsNotNil()
-	assert.Port(pointConfig.InboundConfig.Port).IsValid()
-	assert.Pointer(pointConfig.OutboundConfig).IsNotNil()
-
-	assert.String(pointConfig.InboundConfig.Protocol).Equals("vmess")
-	assert.Pointer(pointConfig.InboundConfig.Settings).IsNotNil()
-
-	assert.String(pointConfig.OutboundConfig.Protocol).Equals("freedom")
-	assert.Pointer(pointConfig.OutboundConfig.Settings).IsNotNil()
-}
-
-func TestDefaultValueOfRandomAllocation(t *testing.T) {
-	assert := assert.On(t)
-
-	rawJson := `{
-    "protocol": "vmess",
-    "port": 1,
-    "settings": {},
-    "allocate": {
-      "strategy": "random"
-    }
-  }`
-
-	inboundDetourConfig := new(InboundDetourConfig)
-	err := json.Unmarshal([]byte(rawJson), inboundDetourConfig)
-	assert.Error(err).IsNil()
-	assert.String(inboundDetourConfig.Allocation.Strategy).Equals(AllocationStrategyRandom)
-	assert.Int(inboundDetourConfig.Allocation.Concurrency).Equals(3)
-	assert.Int(inboundDetourConfig.Allocation.Refresh).Equals(5)
-}

+ 8 - 5
inbound_detour_always.go

@@ -12,11 +12,11 @@ import (
 // Handler for inbound detour connections.
 type InboundDetourHandlerAlways struct {
 	space  app.Space
-	config *InboundDetourConfig
+	config *InboundConnectionConfig
 	ich    []proxy.InboundHandler
 }
 
-func NewInboundDetourHandlerAlways(space app.Space, config *InboundDetourConfig) (*InboundDetourHandlerAlways, error) {
+func NewInboundDetourHandlerAlways(space app.Space, config *InboundConnectionConfig) (*InboundDetourHandlerAlways, error) {
 	handler := &InboundDetourHandlerAlways{
 		space:  space,
 		config: config,
@@ -24,9 +24,12 @@ func NewInboundDetourHandlerAlways(space app.Space, config *InboundDetourConfig)
 	ports := config.PortRange
 	handler.ich = make([]proxy.InboundHandler, 0, ports.To-ports.From+1)
 	for i := ports.FromPort(); i <= ports.ToPort(); i++ {
-		ichConfig := config.Settings
+		ichConfig, err := config.GetTypedSettings()
+		if err != nil {
+			return nil, err
+		}
 		ich, err := proxyregistry.CreateInboundHandler(config.Protocol, space, ichConfig, &proxy.InboundHandlerMeta{
-			Address:                config.ListenOn,
+			Address:                config.ListenOn.AsAddress(),
 			Port:                   i,
 			Tag:                    config.Tag,
 			StreamSettings:         config.StreamSettings,
@@ -43,7 +46,7 @@ func NewInboundDetourHandlerAlways(space app.Space, config *InboundDetourConfig)
 
 func (this *InboundDetourHandlerAlways) GetConnectionHandler() (proxy.InboundHandler, int) {
 	ich := this.ich[dice.Roll(len(this.ich))]
-	return ich, this.config.Allocation.Refresh
+	return ich, int(this.config.GetAllocationStrategyValue().Refresh.GetValue())
 }
 
 func (this *InboundDetourHandlerAlways) Close() {

+ 8 - 8
inbound_detour_dynamic.go

@@ -16,24 +16,24 @@ import (
 type InboundDetourHandlerDynamic struct {
 	sync.RWMutex
 	space       app.Space
-	config      *InboundDetourConfig
+	config      *InboundConnectionConfig
 	portsInUse  map[v2net.Port]bool
 	ichs        []proxy.InboundHandler
 	ich2Recyle  []proxy.InboundHandler
 	lastRefresh time.Time
 }
 
-func NewInboundDetourHandlerDynamic(space app.Space, config *InboundDetourConfig) (*InboundDetourHandlerDynamic, error) {
+func NewInboundDetourHandlerDynamic(space app.Space, config *InboundConnectionConfig) (*InboundDetourHandlerDynamic, error) {
 	handler := &InboundDetourHandlerDynamic{
 		space:      space,
 		config:     config,
 		portsInUse: make(map[v2net.Port]bool),
 	}
-	handler.ichs = make([]proxy.InboundHandler, config.Allocation.Concurrency)
+	handler.ichs = make([]proxy.InboundHandler, config.GetAllocationStrategyValue().Concurrency.GetValue())
 
 	// To test configuration
 	ich, err := proxyregistry.CreateInboundHandler(config.Protocol, space, config.Settings, &proxy.InboundHandlerMeta{
-		Address:                config.ListenOn,
+		Address:                config.ListenOn.AsAddress(),
 		Port:                   0,
 		Tag:                    config.Tag,
 		StreamSettings:         config.StreamSettings,
@@ -64,7 +64,7 @@ func (this *InboundDetourHandlerDynamic) GetConnectionHandler() (proxy.InboundHa
 	this.RLock()
 	defer this.RUnlock()
 	ich := this.ichs[dice.Roll(len(this.ichs))]
-	until := this.config.Allocation.Refresh - int((time.Now().Unix()-this.lastRefresh.Unix())/60/1000)
+	until := int(this.config.GetAllocationStrategyValue().Refresh.GetValue()) - int((time.Now().Unix()-this.lastRefresh.Unix())/60/1000)
 	if until < 0 {
 		until = 0
 	}
@@ -98,13 +98,13 @@ func (this *InboundDetourHandlerDynamic) refresh() error {
 
 	config := this.config
 	this.ich2Recyle = this.ichs
-	newIchs := make([]proxy.InboundHandler, config.Allocation.Concurrency)
+	newIchs := make([]proxy.InboundHandler, config.GetAllocationStrategyValue().Concurrency.GetValue())
 
 	for idx := range newIchs {
 		err := retry.Timed(5, 100).On(func() error {
 			port := this.pickUnusedPort()
 			ich, err := proxyregistry.CreateInboundHandler(config.Protocol, this.space, config.Settings, &proxy.InboundHandlerMeta{
-				Address: config.ListenOn, Port: port, Tag: config.Tag, StreamSettings: config.StreamSettings})
+				Address: config.ListenOn.AsAddress(), Port: port, Tag: config.Tag, StreamSettings: config.StreamSettings})
 			if err != nil {
 				delete(this.portsInUse, port)
 				return err
@@ -140,7 +140,7 @@ func (this *InboundDetourHandlerDynamic) Start() error {
 
 	go func() {
 		for {
-			time.Sleep(time.Duration(this.config.Allocation.Refresh)*time.Minute - 1)
+			time.Sleep(time.Duration(this.config.GetAllocationStrategyValue().Refresh.GetValue())*time.Minute - 1)
 			this.RecyleHandles()
 			err := this.refresh()
 			if err != nil {

+ 4 - 19
proxy/registry/handler_cache.go

@@ -42,7 +42,7 @@ func MustRegisterOutboundHandlerCreator(name string, creator OutboundHandlerFact
 	}
 }
 
-func CreateInboundHandler(name string, space app.Space, rawConfig []byte, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
+func CreateInboundHandler(name string, space app.Space, config interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
 	creator, found := inboundFactories[name]
 	if !found {
 		return nil, common.ErrObjectNotFound
@@ -57,17 +57,10 @@ func CreateInboundHandler(name string, space app.Space, rawConfig []byte, meta *
 		}
 	}
 
-	if len(rawConfig) > 0 {
-		proxyConfig, err := CreateInboundConfig(name, rawConfig)
-		if err != nil {
-			return nil, err
-		}
-		return creator.Create(space, proxyConfig, meta)
-	}
-	return creator.Create(space, nil, meta)
+	return creator.Create(space, config, meta)
 }
 
-func CreateOutboundHandler(name string, space app.Space, rawConfig []byte, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
+func CreateOutboundHandler(name string, space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
 	creator, found := outboundFactories[name]
 	if !found {
 		return nil, common.ErrObjectNotFound
@@ -82,13 +75,5 @@ func CreateOutboundHandler(name string, space app.Space, rawConfig []byte, meta
 		}
 	}
 
-	if len(rawConfig) > 0 {
-		proxyConfig, err := CreateOutboundConfig(name, rawConfig)
-		if err != nil {
-			return nil, err
-		}
-		return creator.Create(space, proxyConfig, meta)
-	}
-
-	return creator.Create(space, nil, meta)
+	return creator.Create(space, config, meta)
 }

+ 62 - 120
v2ray.go

@@ -9,44 +9,33 @@ import (
 	"v2ray.com/core/app/router"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/log"
-	v2net "v2ray.com/core/common/net"
-	"v2ray.com/core/common/retry"
 	"v2ray.com/core/proxy"
 	proxyregistry "v2ray.com/core/proxy/registry"
 )
 
 // Point shell of V2Ray.
 type Point struct {
-	port      v2net.Port
-	listen    v2net.Address
-	ich       proxy.InboundHandler
-	och       proxy.OutboundHandler
-	idh       []InboundDetourHandler
-	taggedIdh map[string]InboundDetourHandler
-	odh       map[string]proxy.OutboundHandler
-	router    *router.Router
-	space     app.Space
+	inboundHandlers       []InboundDetourHandler
+	taggedInboundHandlers map[string]InboundDetourHandler
+
+	outboundHandlers       []proxy.OutboundHandler
+	taggedOutboundHandlers map[string]proxy.OutboundHandler
+
+	router *router.Router
+	space  app.Space
 }
 
 // NewPoint returns a new Point server based on given configuration.
 // The server is not started at this point.
 func NewPoint(pConfig *Config) (*Point, error) {
 	var vpoint = new(Point)
-	vpoint.port = pConfig.InboundConfig.Port
-	if vpoint.port == 0 {
-		vpoint.port = pConfig.Port // Backward compatibility
-	}
-
-	vpoint.listen = pConfig.InboundConfig.ListenOn
 
-	if pConfig.TransportConfig != nil {
-		pConfig.TransportConfig.Apply()
+	if err := pConfig.Transport.Apply(); err != nil {
+		return nil, err
 	}
 
-	if pConfig.LogConfig != nil {
-		if err := pConfig.LogConfig.Apply(); err != nil {
-			return nil, err
-		}
+	if err := pConfig.Log.Apply(); err != nil {
+		return nil, err
 	}
 
 	vpoint.space = app.NewSpace()
@@ -55,13 +44,13 @@ func NewPoint(pConfig *Config) (*Point, error) {
 	outboundHandlerManager := proxyman.NewDefaultOutboundHandlerManager()
 	vpoint.space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager)
 
-	dnsConfig := pConfig.DNSConfig
+	dnsConfig := pConfig.Dns
 	if dnsConfig != nil {
 		dnsServer := dns.NewCacheServer(vpoint.space, dnsConfig)
 		vpoint.space.BindApp(dns.APP_ID, dnsServer)
 	}
 
-	routerConfig := pConfig.RouterConfig
+	routerConfig := pConfig.Router
 	if routerConfig != nil {
 		r := router.NewRouter(routerConfig, vpoint.space)
 		vpoint.space.BindApp(router.APP_ID, r)
@@ -70,84 +59,54 @@ func NewPoint(pConfig *Config) (*Point, error) {
 
 	vpoint.space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(vpoint.space))
 
-	ichConfig := pConfig.InboundConfig.Settings
-	ich, err := proxyregistry.CreateInboundHandler(
-		pConfig.InboundConfig.Protocol, vpoint.space, ichConfig, &proxy.InboundHandlerMeta{
-			Tag:                    "system.inbound",
-			Address:                pConfig.InboundConfig.ListenOn,
-			Port:                   vpoint.port,
-			StreamSettings:         pConfig.InboundConfig.StreamSettings,
-			AllowPassiveConnection: pConfig.InboundConfig.AllowPassiveConnection,
-		})
-	if err != nil {
-		log.Error("Failed to create inbound connection handler: ", err)
-		return nil, err
-	}
-	vpoint.ich = ich
-
-	ochConfig := pConfig.OutboundConfig.Settings
-	och, err := proxyregistry.CreateOutboundHandler(
-		pConfig.OutboundConfig.Protocol, vpoint.space, ochConfig, &proxy.OutboundHandlerMeta{
-			Tag:            "system.outbound",
-			Address:        pConfig.OutboundConfig.SendThrough,
-			StreamSettings: pConfig.OutboundConfig.StreamSettings,
-		})
-	if err != nil {
-		log.Error("Failed to create outbound connection handler: ", err)
-		return nil, err
-	}
-	vpoint.och = och
-	outboundHandlerManager.SetDefaultHandler(och)
-
-	vpoint.taggedIdh = make(map[string]InboundDetourHandler)
-	detours := pConfig.InboundDetours
-	if len(detours) > 0 {
-		vpoint.idh = make([]InboundDetourHandler, len(detours))
-		for idx, detourConfig := range detours {
-			allocConfig := detourConfig.Allocation
-			var detourHandler InboundDetourHandler
-			switch allocConfig.Strategy {
-			case AllocationStrategyAlways:
-				dh, err := NewInboundDetourHandlerAlways(vpoint.space, detourConfig)
-				if err != nil {
-					log.Error("Point: Failed to create detour handler: ", err)
-					return nil, common.ErrBadConfiguration
-				}
-				detourHandler = dh
-			case AllocationStrategyRandom:
-				dh, err := NewInboundDetourHandlerDynamic(vpoint.space, detourConfig)
-				if err != nil {
-					log.Error("Point: Failed to create detour handler: ", err)
-					return nil, common.ErrBadConfiguration
-				}
-				detourHandler = dh
-			default:
-				log.Error("Point: Unknown allocation strategy: ", allocConfig.Strategy)
+	vpoint.inboundHandlers = make([]InboundDetourHandler, 8)
+	vpoint.taggedInboundHandlers = make(map[string]InboundDetourHandler)
+	for _, inbound := range pConfig.Inbound {
+		allocConfig := inbound.GetAllocationStrategyValue()
+		var inboundHandler InboundDetourHandler
+		switch allocConfig.Type {
+		case AllocationStrategy_Always:
+			dh, err := NewInboundDetourHandlerAlways(vpoint.space, inbound)
+			if err != nil {
+				log.Error("Point: Failed to create detour handler: ", err)
 				return nil, common.ErrBadConfiguration
 			}
-			vpoint.idh[idx] = detourHandler
-			if len(detourConfig.Tag) > 0 {
-				vpoint.taggedIdh[detourConfig.Tag] = detourHandler
+			inboundHandler = dh
+		case AllocationStrategy_Random:
+			dh, err := NewInboundDetourHandlerDynamic(vpoint.space, inbound)
+			if err != nil {
+				log.Error("Point: Failed to create detour handler: ", err)
+				return nil, common.ErrBadConfiguration
 			}
+			inboundHandler = dh
+		default:
+			log.Error("Point: Unknown allocation strategy: ", allocConfig.Type)
+			return nil, common.ErrBadConfiguration
+		}
+		vpoint.inboundHandlers = append(vpoint.inboundHandlers, inboundHandler)
+		if len(inbound.Tag) > 0 {
+			vpoint.taggedInboundHandlers[inbound.Tag] = inboundHandler
 		}
 	}
 
-	outboundDetours := pConfig.OutboundDetours
-	if len(outboundDetours) > 0 {
-		vpoint.odh = make(map[string]proxy.OutboundHandler)
-		for _, detourConfig := range outboundDetours {
-			detourHandler, err := proxyregistry.CreateOutboundHandler(
-				detourConfig.Protocol, vpoint.space, detourConfig.Settings, &proxy.OutboundHandlerMeta{
-					Tag:            detourConfig.Tag,
-					Address:        detourConfig.SendThrough,
-					StreamSettings: detourConfig.StreamSettings,
-				})
-			if err != nil {
-				log.Error("Point: Failed to create detour outbound connection handler: ", err)
-				return nil, err
-			}
-			vpoint.odh[detourConfig.Tag] = detourHandler
-			outboundHandlerManager.SetHandler(detourConfig.Tag, detourHandler)
+	vpoint.outboundHandlers = make([]proxy.OutboundHandler, 8)
+	vpoint.taggedOutboundHandlers = make(map[string]proxy.OutboundHandler)
+	for idx, outbound := range pConfig.Outbound {
+		outboundHandler, err := proxyregistry.CreateOutboundHandler(
+			outbound.Protocol, vpoint.space, outbound.Settings, &proxy.OutboundHandlerMeta{
+				Tag:            outbound.Tag,
+				Address:        outbound.SendThrough.AsAddress(),
+				StreamSettings: outbound.StreamSettings,
+			})
+		if err != nil {
+			log.Error("Point: Failed to create detour outbound connection handler: ", err)
+			return nil, err
+		}
+		if idx == 0 {
+			outboundHandlerManager.SetDefaultHandler(outboundHandler)
+		}
+		if len(outbound.Tag) > 0 {
+			outboundHandlerManager.SetHandler(outbound.Tag, outboundHandler)
 		}
 	}
 
@@ -159,44 +118,27 @@ func NewPoint(pConfig *Config) (*Point, error) {
 }
 
 func (this *Point) Close() {
-	this.ich.Close()
-	for _, idh := range this.idh {
-		idh.Close()
+	for _, inbound := range this.inboundHandlers {
+		inbound.Close()
 	}
 }
 
 // Start starts the Point server, and return any error during the process.
 // In the case of any errors, the state of the server is unpredicatable.
 func (this *Point) Start() error {
-	if this.port <= 0 {
-		log.Error("Point: Invalid port ", this.port)
-		return common.ErrBadConfiguration
-	}
-
-	err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
-		err := this.ich.Start()
-		if err != nil {
-			return err
-		}
-		log.Warning("Point: started on port ", this.port)
-		return nil
-	})
-	if err != nil {
-		return err
-	}
-
-	for _, detourHandler := range this.idh {
-		err := detourHandler.Start()
+	for _, inbound := range this.inboundHandlers {
+		err := inbound.Start()
 		if err != nil {
 			return err
 		}
 	}
+	log.Warning("V2Ray started.")
 
 	return nil
 }
 
 func (this *Point) GetHandler(tag string) (proxy.InboundHandler, int) {
-	handler, found := this.taggedIdh[tag]
+	handler, found := this.taggedInboundHandlers[tag]
 	if !found {
 		log.Warning("Point: Unable to find an inbound handler with tag: ", tag)
 		return nil, 0