protobuf for stream settings

This commit is contained in:
Darien Raymond 2016-10-02 23:43:58 +02:00
parent 5ec948f690
commit 1d13f47f9c
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
59 changed files with 1243 additions and 323 deletions

View File

@ -28,8 +28,8 @@ func TestDnsAdd(t *testing.T) {
space,
&proxy.OutboundHandlerMeta{
Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
},
}))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager)

View File

@ -68,7 +68,7 @@ func NewNetworkList(networks collect.StringList) *NetworkList {
}
// HashNetwork returns true if the given network is in this NetworkList.
func (this *NetworkList) HasNetwork(network Network) bool {
func (this NetworkList) HasNetwork(network Network) bool {
for _, value := range this.Network {
if string(value) == string(network) {
return true
@ -76,3 +76,7 @@ func (this *NetworkList) HasNetwork(network Network) bool {
}
return false
}
func (this NetworkList) Get(idx int) Network {
return this.Network[idx]
}

View File

@ -8,6 +8,15 @@ import (
"v2ray.com/core/common/collect"
)
func (this *Network) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {
return err
}
*this = ParseNetwork(str)
return nil
}
func (this *NetworkList) UnmarshalJSON(data []byte) error {
var strlist collect.StringList
if err := json.Unmarshal(data, &strlist); err != nil {

View File

@ -10,6 +10,15 @@ import (
"v2ray.com/core/testing/assert"
)
func TestStringNetwork(t *testing.T) {
assert := assert.On(t)
var network Network
err := json.Unmarshal([]byte(`"tcp"`), &network)
assert.Error(err).IsNil()
assert.Bool(network == Network_TCP).IsTrue()
}
func TestArrayNetworkList(t *testing.T) {
assert := assert.On(t)

View File

@ -6,7 +6,6 @@ import (
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/proxy/registry"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/ray"
)
@ -40,8 +39,10 @@ func (this *BlackHole) Dispatch(destination v2net.Destination, payload *alloc.Bu
type Factory struct{}
func (this *Factory) StreamCapability() internet.StreamConnectionType {
return internet.StreamConnectionTypeRawTCP
func (this *Factory) StreamCapability() v2net.NetworkList {
return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
}
func (this *Factory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {

View File

@ -194,8 +194,10 @@ func (this *DokodemoDoor) HandleTCPConnection(conn internet.Connection) {
type Factory struct{}
func (this *Factory) StreamCapability() internet.StreamConnectionType {
return internet.StreamConnectionTypeRawTCP
func (this *Factory) StreamCapability() v2net.NetworkList {
return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
}
func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -44,8 +44,8 @@ func TestDokodemoTCP(t *testing.T) {
space,
&proxy.OutboundHandlerMeta{
Address: v2net.LocalHostIP,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
},
}))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm)
@ -65,8 +65,8 @@ func TestDokodemoTCP(t *testing.T) {
}, space, &proxy.InboundHandlerMeta{
Address: v2net.LocalHostIP,
Port: port,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
}})
defer dokodemo.Close()
@ -119,8 +119,8 @@ func TestDokodemoUDP(t *testing.T) {
space,
&proxy.OutboundHandlerMeta{
Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
}}))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm)
@ -139,8 +139,8 @@ func TestDokodemoUDP(t *testing.T) {
}, space, &proxy.InboundHandlerMeta{
Address: v2net.LocalHostIP,
Port: port,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
}})
defer dokodemo.Close()

View File

@ -129,8 +129,10 @@ func (this *FreedomConnection) Dispatch(destination v2net.Destination, payload *
type FreedomFactory struct{}
func (this *FreedomFactory) StreamCapability() internet.StreamConnectionType {
return internet.StreamConnectionTypeRawTCP
func (this *FreedomFactory) StreamCapability() v2net.NetworkList {
return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
}
func (this *FreedomFactory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {

View File

@ -40,8 +40,8 @@ func TestSinglePacket(t *testing.T) {
space,
&proxy.OutboundHandlerMeta{
Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
},
})
space.Initialize()
@ -68,8 +68,8 @@ func TestUnreachableDestination(t *testing.T) {
app.NewSpace(),
&proxy.OutboundHandlerMeta{
Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
},
})
traffic := ray.NewRay()
@ -104,8 +104,8 @@ func TestIPResolution(t *testing.T) {
space,
&proxy.OutboundHandlerMeta{
Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
},
})

View File

@ -264,8 +264,10 @@ func (this *Server) handlePlainHTTP(request *http.Request, session *proxy.Sessio
type ServerFactory struct{}
func (this *ServerFactory) StreamCapability() internet.StreamConnectionType {
return internet.StreamConnectionTypeRawTCP
func (this *ServerFactory) StreamCapability() v2net.NetworkList {
return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
}
func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -63,8 +63,8 @@ func TestNormalGetRequest(t *testing.T) {
&proxy.InboundHandlerMeta{
Address: v2net.LocalHostIP,
Port: port,
StreamSettings: &internet.StreamSettings{
Type: internet.StreamConnectionTypeRawTCP,
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_RawTCP,
}})
defer httpProxy.Close()

View File

@ -27,13 +27,13 @@ type InboundHandlerMeta struct {
Address v2net.Address
Port v2net.Port
AllowPassiveConnection bool
StreamSettings *internet.StreamSettings
StreamSettings *internet.StreamConfig
}
type OutboundHandlerMeta struct {
Tag string
Address v2net.Address
StreamSettings *internet.StreamSettings
StreamSettings *internet.StreamConfig
}
// An InboundHandler handles inbound network connections to V2Ray.

View File

@ -2,16 +2,16 @@ package registry
import (
"v2ray.com/core/app"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
)
type InboundHandlerFactory interface {
StreamCapability() internet.StreamConnectionType
StreamCapability() v2net.NetworkList
Create(space app.Space, config interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error)
}
type OutboundHandlerFactory interface {
StreamCapability() internet.StreamConnectionType
StreamCapability() v2net.NetworkList
Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error)
}

View File

@ -1,6 +1,8 @@
package registry
import (
"errors"
"v2ray.com/core/app"
"v2ray.com/core/common"
"v2ray.com/core/proxy"
@ -46,11 +48,13 @@ func CreateInboundHandler(name string, space app.Space, rawConfig []byte, meta *
return nil, common.ErrObjectNotFound
}
if meta.StreamSettings == nil {
meta.StreamSettings = &internet.StreamSettings{
Type: creator.StreamCapability(),
meta.StreamSettings = &internet.StreamConfig{
Network: creator.StreamCapability().Get(0),
}
} else {
meta.StreamSettings.Type &= creator.StreamCapability()
if !creator.StreamCapability().HasNetwork(meta.StreamSettings.Network) {
return nil, errors.New("Proxy|Registry: Invalid network: " + meta.StreamSettings.Network.String())
}
}
if len(rawConfig) > 0 {
@ -69,11 +73,13 @@ func CreateOutboundHandler(name string, space app.Space, rawConfig []byte, meta
return nil, common.ErrObjectNotFound
}
if meta.StreamSettings == nil {
meta.StreamSettings = &internet.StreamSettings{
Type: creator.StreamCapability(),
meta.StreamSettings = &internet.StreamConfig{
Network: creator.StreamCapability().Get(0),
}
} else {
meta.StreamSettings.Type &= creator.StreamCapability()
if !creator.StreamCapability().HasNetwork(meta.StreamSettings.Network) {
return nil, errors.New("Proxy|Registry: Invalid network: " + meta.StreamSettings.Network.String())
}
}
if len(rawConfig) > 0 {

View File

@ -278,8 +278,10 @@ func (this *Server) handleConnection(conn internet.Connection) {
type ServerFactory struct{}
func (this *ServerFactory) StreamCapability() internet.StreamConnectionType {
return internet.StreamConnectionTypeRawTCP
func (this *ServerFactory) StreamCapability() v2net.NetworkList {
return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
}
func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -315,8 +315,10 @@ func (this *Server) transport(reader io.Reader, writer io.Writer, session *proxy
type ServerFactory struct{}
func (this *ServerFactory) StreamCapability() internet.StreamConnectionType {
return internet.StreamConnectionTypeRawTCP
func (this *ServerFactory) StreamCapability() v2net.NetworkList {
return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
}
func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -249,8 +249,10 @@ func (this *VMessInboundHandler) HandleConnection(connection internet.Connection
type Factory struct{}
func (this *Factory) StreamCapability() internet.StreamConnectionType {
return internet.StreamConnectionTypeRawTCP | internet.StreamConnectionTypeTCP | internet.StreamConnectionTypeKCP | internet.StreamConnectionTypeWebSocket
func (this *Factory) StreamCapability() v2net.NetworkList {
return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_TCP, v2net.Network_KCP, v2net.Network_WebSocket},
}
}
func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -160,8 +160,10 @@ func (this *VMessOutboundHandler) handleResponse(session *encoding.ClientSession
type Factory struct{}
func (this *Factory) StreamCapability() internet.StreamConnectionType {
return internet.StreamConnectionTypeRawTCP | internet.StreamConnectionTypeTCP | internet.StreamConnectionTypeKCP | internet.StreamConnectionTypeWebSocket
func (this *Factory) StreamCapability() v2net.NetworkList {
return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_TCP, v2net.Network_KCP, v2net.Network_WebSocket},
}
}
func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {

View File

@ -13,7 +13,7 @@ import (
type InboundConnectionConfig struct {
Port v2net.Port
ListenOn v2net.Address
StreamSettings *internet.StreamSettings
StreamSettings *internet.StreamConfig
Protocol string
Settings []byte
AllowPassiveConnection bool
@ -22,7 +22,7 @@ type InboundConnectionConfig struct {
type OutboundConnectionConfig struct {
Protocol string
SendThrough v2net.Address
StreamSettings *internet.StreamSettings
StreamSettings *internet.StreamConfig
Settings []byte
}
@ -50,7 +50,7 @@ type InboundDetourConfig struct {
ListenOn v2net.Address
Tag string
Allocation *InboundDetourAllocationConfig
StreamSettings *internet.StreamSettings
StreamSettings *internet.StreamConfig
Settings []byte
AllowPassiveConnection bool
}
@ -58,7 +58,7 @@ type InboundDetourConfig struct {
type OutboundDetourConfig struct {
Protocol string
SendThrough v2net.Address
StreamSettings *internet.StreamSettings
StreamSettings *internet.StreamConfig
Tag string
Settings []byte
}

View File

@ -73,12 +73,12 @@ func (this *Config) UnmarshalJSON(data []byte) error {
func (this *InboundConnectionConfig) UnmarshalJSON(data []byte) error {
type JsonConfig struct {
Port uint16 `json:"port"`
Listen *v2net.AddressPB `json:"listen"`
Protocol string `json:"protocol"`
StreamSetting *internet.StreamSettings `json:"streamSettings"`
Settings json.RawMessage `json:"settings"`
AllowPassive bool `json:"allowPassive"`
Port uint16 `json:"port"`
Listen *v2net.AddressPB `json:"listen"`
Protocol string `json:"protocol"`
StreamSetting *internet.StreamConfig `json:"streamSettings"`
Settings json.RawMessage `json:"settings"`
AllowPassive bool `json:"allowPassive"`
}
jsonConfig := new(JsonConfig)
@ -105,10 +105,10 @@ func (this *InboundConnectionConfig) UnmarshalJSON(data []byte) error {
func (this *OutboundConnectionConfig) UnmarshalJSON(data []byte) error {
type JsonConnectionConfig struct {
Protocol string `json:"protocol"`
SendThrough *v2net.AddressPB `json:"sendThrough"`
StreamSetting *internet.StreamSettings `json:"streamSettings"`
Settings json.RawMessage `json:"settings"`
Protocol string `json:"protocol"`
SendThrough *v2net.AddressPB `json:"sendThrough"`
StreamSetting *internet.StreamConfig `json:"streamSettings"`
Settings json.RawMessage `json:"settings"`
}
jsonConfig := new(JsonConnectionConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil {
@ -194,7 +194,7 @@ func (this *InboundDetourConfig) UnmarshalJSON(data []byte) error {
Settings json.RawMessage `json:"settings"`
Tag string `json:"tag"`
Allocation *InboundDetourAllocationConfig `json:"allocate"`
StreamSetting *internet.StreamSettings `json:"streamSettings"`
StreamSetting *internet.StreamConfig `json:"streamSettings"`
AllowPassive bool `json:"allowPassive"`
}
jsonConfig := new(JsonInboundDetourConfig)
@ -232,11 +232,11 @@ func (this *InboundDetourConfig) UnmarshalJSON(data []byte) error {
func (this *OutboundDetourConfig) UnmarshalJSON(data []byte) error {
type JsonOutboundDetourConfig struct {
Protocol string `json:"protocol"`
SendThrough *v2net.AddressPB `json:"sendThrough"`
Tag string `json:"tag"`
Settings json.RawMessage `json:"settings"`
StreamSetting *internet.StreamSettings `json:"streamSettings"`
Protocol string `json:"protocol"`
SendThrough *v2net.AddressPB `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 {

View File

@ -1,26 +1,11 @@
package transport
import (
"v2ray.com/core/transport/internet/kcp"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/ws"
"v2ray.com/core/transport/internet"
)
// Config for V2Ray transport layer.
type Config struct {
tcpConfig *tcp.Config
kcpConfig kcp.Config
wsConfig *ws.Config
}
// Apply applies this Config.
func (this *Config) Apply() error {
if this.tcpConfig != nil {
this.tcpConfig.Apply()
}
this.kcpConfig.Apply()
if this.wsConfig != nil {
this.wsConfig.Apply()
}
internet.ApplyGlobalNetworkSettings(this.NetworkSettings)
return nil
}

67
transport/config.pb.go Normal file
View File

@ -0,0 +1,67 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/config.proto
// DO NOT EDIT!
/*
Package transport is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/config.proto
It has these top-level messages:
Config
*/
package transport
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import v2ray_core_transport_internet "v2ray.com/core/transport/internet"
// 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 Config struct {
NetworkSettings []*v2ray_core_transport_internet.NetworkSettings `protobuf:"bytes,1,rep,name=network_settings,json=networkSettings" json:"network_settings,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{0} }
func (m *Config) GetNetworkSettings() []*v2ray_core_transport_internet.NetworkSettings {
if m != nil {
return m.NetworkSettings
}
return nil
}
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.transport.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/transport/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 165 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x2d, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x29, 0x4a, 0xcc, 0x2b,
0x2e, 0xc8, 0x2f, 0x2a, 0xd1, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f,
0xc9, 0x17, 0x12, 0x81, 0x29, 0x2b, 0x4a, 0xd5, 0x83, 0x2b, 0x91, 0xd2, 0xc3, 0xa9, 0x39, 0x33,
0xaf, 0x24, 0xb5, 0x28, 0x2f, 0x15, 0xd5, 0x14, 0xa5, 0x64, 0x2e, 0x36, 0x67, 0x30, 0x5f, 0x28,
0x92, 0x4b, 0x20, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x3b, 0xbe, 0x38, 0xb5, 0xa4, 0x24, 0x33,
0x2f, 0xbd, 0x58, 0x82, 0x51, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x4f, 0x0f, 0x9b, 0x55, 0x7a, 0x30,
0x03, 0xf5, 0xfc, 0x20, 0xda, 0x82, 0xa1, 0xba, 0x82, 0xf8, 0xf3, 0x50, 0x05, 0x9c, 0x8c, 0xb8,
0x24, 0x92, 0xf3, 0x73, 0xb1, 0x9a, 0xe2, 0xc4, 0x0d, 0xb1, 0x3e, 0x00, 0xe4, 0x9a, 0x28, 0x4e,
0xb8, 0x78, 0x12, 0x1b, 0xd8, 0x7d, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0c, 0xfb, 0x2d,
0x01, 0x0e, 0x01, 0x00, 0x00,
}

View File

@ -5,6 +5,8 @@ option go_package = "transport";
option java_package = "com.v2ray.core.transport";
option java_outer_classname = "ConfigProto";
import "v2ray.com/core/transport/internet/config.proto";
message Config {
repeated v2ray.core.transport.internet.NetworkSettings network_settings = 1;
}

View File

@ -5,23 +5,57 @@ package transport
import (
"encoding/json"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/kcp"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/ws"
"github.com/golang/protobuf/ptypes"
)
func (this *Config) UnmarshalJSON(data []byte) error {
type JsonConfig struct {
TCPConfig *tcp.Config `json:"tcpSettings"`
KCPConfig kcp.Config `json:"kcpSettings"`
KCPConfig *kcp.Config `json:"kcpSettings"`
WSConfig *ws.Config `json:"wsSettings"`
}
jsonConfig := &JsonConfig{}
if err := json.Unmarshal(data, jsonConfig); err != nil {
return err
}
this.tcpConfig = jsonConfig.TCPConfig
this.kcpConfig = jsonConfig.KCPConfig
this.wsConfig = jsonConfig.WSConfig
if jsonConfig.TCPConfig != nil {
any, err := ptypes.MarshalAny(jsonConfig.TCPConfig)
if err != nil {
return err
}
this.NetworkSettings = append(this.NetworkSettings, &internet.NetworkSettings{
Network: v2net.Network_TCP,
Settings: any,
})
}
if jsonConfig.KCPConfig != nil {
any, err := ptypes.MarshalAny(jsonConfig.KCPConfig)
if err != nil {
return err
}
this.NetworkSettings = append(this.NetworkSettings, &internet.NetworkSettings{
Network: v2net.Network_KCP,
Settings: any,
})
}
if jsonConfig.WSConfig != nil {
any, err := ptypes.MarshalAny(jsonConfig.WSConfig)
if err != nil {
return err
}
this.NetworkSettings = append(this.NetworkSettings, &internet.NetworkSettings{
Network: v2net.Network_WebSocket,
Settings: any,
})
}
return nil
}

View File

@ -7,9 +7,13 @@ Package internet is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/internet/authenticator.proto
v2ray.com/core/transport/internet/config.proto
It has these top-level messages:
AuthenticatorConfig
SecuritySettings
NetworkSettings
StreamConfig
*/
package internet

View File

@ -0,0 +1,108 @@
package internet
import (
"errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
v2tls "v2ray.com/core/transport/internet/tls"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
)
type NetworkConfigCreator func() proto.Message
var (
globalNetworkConfigCreatorCache = make(map[v2net.Network]NetworkConfigCreator)
globalSecurityConfigCreatorCache = make(map[SecurityType]NetworkConfigCreator)
globalNetworkSettings []*NetworkSettings
ErrUnconfiguredNetwork = errors.New("Network config creator not set.")
)
func RegisterNetworkConfigCreator(network v2net.Network, creator NetworkConfigCreator) error {
// TODO: check duplicate
globalNetworkConfigCreatorCache[network] = creator
return nil
}
func CreateNetworkConfig(network v2net.Network) (proto.Message, error) {
creator, ok := globalNetworkConfigCreatorCache[network]
if !ok {
log.Warning("Internet: Network config creator not found: ", network)
return nil, ErrUnconfiguredNetwork
}
return creator(), nil
}
func RegisterSecurityConfigCreator(securityType SecurityType, creator NetworkConfigCreator) error {
globalSecurityConfigCreatorCache[securityType] = creator
return nil
}
func CreateSecurityConfig(securityType SecurityType) (proto.Message, error) {
creator, ok := globalSecurityConfigCreatorCache[securityType]
if !ok {
log.Warning("Internet: Security config creator not found: ", securityType)
return nil, ErrUnconfiguredNetwork
}
return creator(), nil
}
func (this *NetworkSettings) GetTypedSettings() (interface{}, error) {
message, err := CreateNetworkConfig(this.Network)
if err != nil {
return nil, err
}
if err := ptypes.UnmarshalAny(this.Settings, message); err != nil {
return nil, err
}
return message, nil
}
func (this *SecuritySettings) GetTypeSettings() (interface{}, error) {
message, err := CreateSecurityConfig(this.Type)
if err != nil {
return nil, err
}
if err := ptypes.UnmarshalAny(this.Settings, message); err != nil {
return nil, err
}
return message, nil
}
func (this *StreamConfig) GetEffectiveNetworkSettings() (interface{}, error) {
for _, settings := range this.NetworkSettings {
if settings.Network == this.Network {
return settings.GetTypedSettings()
}
}
for _, settings := range globalNetworkSettings {
if settings.Network == this.Network {
return settings.GetTypedSettings()
}
}
return CreateNetworkConfig(this.Network)
}
func (this *StreamConfig) GetEffectiveSecuritySettings() (interface{}, error) {
for _, settings := range this.SecuritySettings {
if settings.Type == this.SecurityType {
return settings.GetTypeSettings()
}
}
return CreateSecurityConfig(this.SecurityType)
}
func ApplyGlobalNetworkSettings(settings []*NetworkSettings) error {
globalNetworkSettings = settings
return nil
}
func init() {
RegisterSecurityConfigCreator(SecurityType_TLS, func() proto.Message {
return new(v2tls.Config)
})
}

View File

@ -0,0 +1,132 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/config.proto
// DO NOT EDIT!
package internet
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import v2ray_core_common_net "v2ray.com/core/common/net"
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
type SecurityType int32
const (
SecurityType_None SecurityType = 0
SecurityType_TLS SecurityType = 1
)
var SecurityType_name = map[int32]string{
0: "None",
1: "TLS",
}
var SecurityType_value = map[string]int32{
"None": 0,
"TLS": 1,
}
func (x SecurityType) String() string {
return proto.EnumName(SecurityType_name, int32(x))
}
func (SecurityType) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
type SecuritySettings struct {
Type SecurityType `protobuf:"varint,1,opt,name=type,enum=v2ray.core.transport.internet.SecurityType" json:"type,omitempty"`
Settings *google_protobuf.Any `protobuf:"bytes,2,opt,name=settings" json:"settings,omitempty"`
}
func (m *SecuritySettings) Reset() { *m = SecuritySettings{} }
func (m *SecuritySettings) String() string { return proto.CompactTextString(m) }
func (*SecuritySettings) ProtoMessage() {}
func (*SecuritySettings) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
func (m *SecuritySettings) GetSettings() *google_protobuf.Any {
if m != nil {
return m.Settings
}
return nil
}
type NetworkSettings struct {
Network v2ray_core_common_net.Network `protobuf:"varint,1,opt,name=network,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
Settings *google_protobuf.Any `protobuf:"bytes,2,opt,name=settings" json:"settings,omitempty"`
}
func (m *NetworkSettings) Reset() { *m = NetworkSettings{} }
func (m *NetworkSettings) String() string { return proto.CompactTextString(m) }
func (*NetworkSettings) ProtoMessage() {}
func (*NetworkSettings) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} }
func (m *NetworkSettings) GetSettings() *google_protobuf.Any {
if m != nil {
return m.Settings
}
return nil
}
type StreamConfig struct {
Network v2ray_core_common_net.Network `protobuf:"varint,1,opt,name=network,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
NetworkSettings []*NetworkSettings `protobuf:"bytes,2,rep,name=network_settings,json=networkSettings" json:"network_settings,omitempty"`
SecurityType SecurityType `protobuf:"varint,3,opt,name=security_type,json=securityType,enum=v2ray.core.transport.internet.SecurityType" json:"security_type,omitempty"`
SecuritySettings []*SecuritySettings `protobuf:"bytes,4,rep,name=security_settings,json=securitySettings" json:"security_settings,omitempty"`
}
func (m *StreamConfig) Reset() { *m = StreamConfig{} }
func (m *StreamConfig) String() string { return proto.CompactTextString(m) }
func (*StreamConfig) ProtoMessage() {}
func (*StreamConfig) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} }
func (m *StreamConfig) GetNetworkSettings() []*NetworkSettings {
if m != nil {
return m.NetworkSettings
}
return nil
}
func (m *StreamConfig) GetSecuritySettings() []*SecuritySettings {
if m != nil {
return m.SecuritySettings
}
return nil
}
func init() {
proto.RegisterType((*SecuritySettings)(nil), "v2ray.core.transport.internet.SecuritySettings")
proto.RegisterType((*NetworkSettings)(nil), "v2ray.core.transport.internet.NetworkSettings")
proto.RegisterType((*StreamConfig)(nil), "v2ray.core.transport.internet.StreamConfig")
proto.RegisterEnum("v2ray.core.transport.internet.SecurityType", SecurityType_name, SecurityType_value)
}
func init() { proto.RegisterFile("v2ray.com/core/transport/internet/config.proto", fileDescriptor1) }
var fileDescriptor1 = []byte{
// 347 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x91, 0x4f, 0x4b, 0xc3, 0x40,
0x10, 0xc5, 0x4d, 0x5b, 0x6c, 0x99, 0x56, 0x1b, 0x83, 0x87, 0x5a, 0x50, 0xda, 0x5e, 0x0c, 0x8a,
0xbb, 0x12, 0x2f, 0xde, 0x44, 0xbd, 0x4a, 0x91, 0xa4, 0x17, 0x45, 0x28, 0x69, 0x98, 0x86, 0xa0,
0xd9, 0x09, 0x9b, 0xad, 0x92, 0x83, 0x47, 0x3f, 0xa1, 0x5f, 0x48, 0x9a, 0x7f, 0x84, 0x1c, 0xea,
0xbf, 0xdb, 0x6e, 0xf2, 0xe6, 0xcd, 0x6f, 0xdf, 0x03, 0xf6, 0x6a, 0x49, 0x37, 0x61, 0x1e, 0x85,
0xdc, 0x23, 0x89, 0x5c, 0x49, 0x57, 0xc4, 0x11, 0x49, 0xc5, 0x03, 0xa1, 0x50, 0x0a, 0x54, 0xdc,
0x23, 0xb1, 0x0c, 0x7c, 0x16, 0x49, 0x52, 0x64, 0x1c, 0x16, 0x7a, 0x89, 0xac, 0xd4, 0xb2, 0x42,
0x3b, 0x3c, 0xae, 0xd9, 0x79, 0x14, 0x86, 0x24, 0xf8, 0xda, 0x46, 0xa0, 0x7a, 0x23, 0xf9, 0x9c,
0xf9, 0x0c, 0x0f, 0x7c, 0x22, 0xff, 0x05, 0x79, 0x7a, 0x5b, 0xac, 0x96, 0xdc, 0x15, 0x49, 0xf6,
0x6b, 0xf2, 0xa1, 0x81, 0xee, 0xa0, 0xb7, 0x92, 0x81, 0x4a, 0x1c, 0x54, 0x2a, 0x10, 0x7e, 0x6c,
0x5c, 0x41, 0x4b, 0x25, 0x11, 0x0e, 0xb4, 0x91, 0x66, 0xee, 0x5a, 0xa7, 0x6c, 0x23, 0x06, 0x2b,
0xc6, 0x67, 0x49, 0x84, 0x76, 0x3a, 0x68, 0x9c, 0x43, 0x27, 0xce, 0xcd, 0x06, 0x8d, 0x91, 0x66,
0x76, 0xad, 0x7d, 0x96, 0x31, 0xb0, 0x82, 0x81, 0x5d, 0x8b, 0xc4, 0x2e, 0x55, 0x93, 0x77, 0xe8,
0x4f, 0x33, 0xe6, 0x92, 0xe2, 0x12, 0xda, 0xf9, 0x33, 0x72, 0x90, 0xa3, 0x2a, 0x48, 0xf6, 0x58,
0xb6, 0x06, 0xc8, 0x07, 0xed, 0x42, 0xfe, 0x87, 0xf5, 0x9f, 0x0d, 0xe8, 0x39, 0x4a, 0xa2, 0x1b,
0xde, 0xa6, 0x05, 0xfc, 0x63, 0xf9, 0x03, 0xe8, 0xf9, 0x71, 0x5e, 0x81, 0x68, 0x9a, 0x5d, 0x8b,
0x7d, 0x13, 0x64, 0x2d, 0x00, 0xbb, 0x2f, 0x6a, 0x89, 0xdc, 0xc3, 0x4e, 0x9c, 0x87, 0x3d, 0x4f,
0x0b, 0x6a, 0xfe, 0xbe, 0xa0, 0x5e, 0x5c, 0xb9, 0x19, 0x4f, 0xb0, 0x57, 0x3a, 0x96, 0xb4, 0xad,
0x94, 0x96, 0xff, 0xd0, 0xb5, 0xc4, 0xd5, 0xe3, 0xda, 0x97, 0x93, 0x31, 0xf4, 0xaa, 0xbb, 0x8d,
0x0e, 0xb4, 0xa6, 0x24, 0x50, 0xdf, 0x32, 0xda, 0xd0, 0x9c, 0xdd, 0x39, 0xba, 0x76, 0x73, 0x06,
0x63, 0x8f, 0xc2, 0xcd, 0xab, 0x1e, 0x3b, 0xc5, 0x69, 0xb1, 0x9d, 0xf6, 0x77, 0xf1, 0x15, 0x00,
0x00, 0xff, 0xff, 0xb2, 0x2e, 0x36, 0x52, 0x4a, 0x03, 0x00, 0x00,
}

View File

@ -0,0 +1,31 @@
syntax = "proto3";
package v2ray.core.transport.internet;
option go_package = "internet";
option java_package = "com.v2ray.core.transport.internet";
import "v2ray.com/core/common/net/network.proto";
import "google/protobuf/any.proto";
enum SecurityType {
None = 0;
TLS = 1;
}
message SecuritySettings {
SecurityType type = 1;
google.protobuf.Any settings = 2;
}
message NetworkSettings {
v2ray.core.common.net.Network network = 1;
google.protobuf.Any settings = 2;
}
message StreamConfig {
v2ray.core.common.net.Network network = 1;
repeated NetworkSettings network_settings = 2;
SecurityType security_type = 3;
repeated SecuritySettings security_settings = 4;
}

View File

@ -1,7 +1,6 @@
package internet
import (
"crypto/tls"
"net"
)
@ -12,56 +11,6 @@ type Reusable interface {
SetReusable(reuse bool)
}
type StreamConnectionType int
const (
StreamConnectionTypeRawTCP StreamConnectionType = 1
StreamConnectionTypeTCP StreamConnectionType = 2
StreamConnectionTypeKCP StreamConnectionType = 4
StreamConnectionTypeWebSocket StreamConnectionType = 8
)
type StreamSecurityType int
const (
StreamSecurityTypeNone StreamSecurityType = 0
StreamSecurityTypeTLS StreamSecurityType = 1
)
var (
globalSessionCache = tls.NewLRUClientSessionCache(128)
)
type TLSSettings struct {
AllowInsecure bool
Certs []tls.Certificate
}
func (this *TLSSettings) GetTLSConfig() *tls.Config {
config := &tls.Config{
ClientSessionCache: globalSessionCache,
}
if this == nil {
return config
}
config.InsecureSkipVerify = this.AllowInsecure
config.Certificates = this.Certs
config.BuildNameToCertificate()
return config
}
type StreamSettings struct {
Type StreamConnectionType
Security StreamSecurityType
TLSSettings *TLSSettings
}
func (this *StreamSettings) IsCapableOf(streamType StreamConnectionType) bool {
return (this.Type & streamType) == streamType
}
type Connection interface {
net.Conn
Reusable

View File

@ -3,65 +3,42 @@
package internet
import (
"crypto/tls"
"encoding/json"
"errors"
"strings"
"errors"
"github.com/golang/protobuf/ptypes"
v2net "v2ray.com/core/common/net"
v2tls "v2ray.com/core/transport/internet/tls"
)
func (this *TLSSettings) UnmarshalJSON(data []byte) error {
type JSONCertConfig struct {
CertFile string `json:"certificateFile"`
KeyFile string `json:"keyFile"`
}
func (this *StreamConfig) UnmarshalJSON(data []byte) error {
type JSONConfig struct {
Insecure bool `json:"allowInsecure"`
Certs []*JSONCertConfig `json:"certificates"`
Network *v2net.Network `json:"network"`
Security string `json:"security"`
TLSSettings *v2tls.Config `json:"tlsSettings"`
}
this.Network = v2net.Network_RawTCP
jsonConfig := new(JSONConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil {
return err
}
this.Certs = make([]tls.Certificate, len(jsonConfig.Certs))
for idx, certConf := range jsonConfig.Certs {
cert, err := tls.LoadX509KeyPair(certConf.CertFile, certConf.KeyFile)
if err != nil {
return errors.New("Internet|TLS: Failed to load certificate file: " + err.Error())
}
this.Certs[idx] = cert
if jsonConfig.Network != nil {
this.Network = *jsonConfig.Network
}
this.AllowInsecure = jsonConfig.Insecure
return nil
}
func (this *StreamSettings) UnmarshalJSON(data []byte) error {
type JSONConfig struct {
Network v2net.NetworkList `json:"network"`
Security string `json:"security"`
TLSSettings *TLSSettings `json:"tlsSettings"`
}
this.Type = StreamConnectionTypeRawTCP
jsonConfig := new(JSONConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil {
return err
}
if jsonConfig.Network.HasNetwork(v2net.Network_KCP) {
this.Type |= StreamConnectionTypeKCP
}
if jsonConfig.Network.HasNetwork(v2net.Network_WebSocket) {
this.Type |= StreamConnectionTypeWebSocket
}
if jsonConfig.Network.HasNetwork(v2net.Network_TCP) {
this.Type |= StreamConnectionTypeTCP
}
this.Security = StreamSecurityTypeNone
this.SecurityType = SecurityType_None
if strings.ToLower(jsonConfig.Security) == "tls" {
this.Security = StreamSecurityTypeTLS
this.SecurityType = SecurityType_TLS
}
if jsonConfig.TLSSettings != nil {
this.TLSSettings = jsonConfig.TLSSettings
anyTLSSettings, err := ptypes.MarshalAny(jsonConfig.TLSSettings)
if err != nil {
return errors.New("Internet: Failed to parse TLS settings: " + err.Error())
}
this.SecuritySettings = append(this.SecuritySettings, &SecuritySettings{
Type: SecurityType_TLS,
Settings: anyTLSSettings,
})
}
return nil
}

View File

@ -12,7 +12,7 @@ var (
)
type DialerOptions struct {
Stream *StreamSettings
Stream *StreamConfig
}
type Dialer func(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error)
@ -25,7 +25,7 @@ var (
WSDialer Dialer
)
func Dial(src v2net.Address, dest v2net.Destination, settings *StreamSettings) (Connection, error) {
func Dial(src v2net.Address, dest v2net.Destination, settings *StreamConfig) (Connection, error) {
var connection Connection
var err error
@ -33,16 +33,16 @@ func Dial(src v2net.Address, dest v2net.Destination, settings *StreamSettings) (
Stream: settings,
}
if dest.Network == v2net.Network_TCP {
switch {
case settings.IsCapableOf(StreamConnectionTypeTCP):
switch settings.Network {
case v2net.Network_TCP:
connection, err = TCPDialer(src, dest, dialerOptions)
case settings.IsCapableOf(StreamConnectionTypeKCP):
case v2net.Network_KCP:
connection, err = KCPDialer(src, dest, dialerOptions)
case settings.IsCapableOf(StreamConnectionTypeWebSocket):
case v2net.Network_WebSocket:
connection, err = WSDialer(src, dest, dialerOptions)
// This check has to be the last one.
case settings.IsCapableOf(StreamConnectionTypeRawTCP):
case v2net.Network_RawTCP:
connection, err = RawTCPDialer(src, dest, dialerOptions)
default:
return nil, ErrUnsupportedStreamType

View File

@ -1,7 +1,10 @@
package kcp
import (
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
"github.com/golang/protobuf/proto"
)
func (this *MTU) GetValue() uint32 {
@ -46,10 +49,6 @@ func (this *ReadBuffer) GetSize() uint32 {
return this.Size
}
func (this *Config) Apply() {
effectiveConfig = *this
}
func (this *Config) GetAuthenticator() (internet.Authenticator, error) {
auth := NewSimpleAuthenticator()
if this.HeaderConfig != nil {
@ -86,6 +85,8 @@ func (this *Config) GetReceivingBufferSize() uint32 {
return this.GetReceivingInFlightSize() + this.ReadBuffer.GetSize()/this.Mtu.GetValue()
}
var (
effectiveConfig Config
)
func init() {
internet.RegisterNetworkConfigCreator(v2net.Network_KCP, func() proto.Message {
return new(Config)
})
}

View File

@ -129,6 +129,7 @@ type Connection struct {
since int64
dataInputCond *sync.Cond
dataOutputCond *sync.Cond
Config *Config
conv uint16
state State
@ -149,7 +150,7 @@ type Connection struct {
}
// NewConnection create a new KCP connection between local and remote.
func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, remote *net.UDPAddr, block internet.Authenticator) *Connection {
func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, remote *net.UDPAddr, block internet.Authenticator, config *Config) *Connection {
log.Info("KCP|Connection: creating connection ", conv)
conn := new(Connection)
@ -160,10 +161,12 @@ func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr,
conn.since = nowMillisec()
conn.dataInputCond = sync.NewCond(new(sync.Mutex))
conn.dataOutputCond = sync.NewCond(new(sync.Mutex))
conn.Config = config
authWriter := &AuthenticationWriter{
Authenticator: block,
Writer: writerCloser,
Config: config,
}
conn.conv = conv
conn.output = NewSegmentWriter(authWriter)
@ -171,12 +174,12 @@ func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr,
conn.mss = authWriter.Mtu() - DataSegmentOverhead
conn.roundTrip = &RoundTripInfo{
rto: 100,
minRtt: effectiveConfig.Tti.GetValue(),
minRtt: config.Tti.GetValue(),
}
conn.interval = effectiveConfig.Tti.GetValue()
conn.interval = config.Tti.GetValue()
conn.receivingWorker = NewReceivingWorker(conn)
conn.fastresend = 2
conn.congestionControl = effectiveConfig.Congestion
conn.congestionControl = config.Congestion
conn.sendingWorker = NewSendingWorker(conn)
go conn.updateTask()
@ -366,7 +369,7 @@ func (this *Connection) updateTask() {
for this.State() != StateTerminated {
this.flush()
interval := time.Duration(effectiveConfig.Tti.GetValue()) * time.Millisecond
interval := time.Duration(this.Config.Tti.GetValue()) * time.Millisecond
if this.State() == StateTerminating {
interval = time.Second
}

View File

@ -27,7 +27,7 @@ func (this *NoOpWriteCloser) Close() error {
func TestConnectionReadTimeout(t *testing.T) {
assert := assert.On(t)
conn := NewConnection(1, &NoOpWriteCloser{}, nil, nil, NewSimpleAuthenticator())
conn := NewConnection(1, &NoOpWriteCloser{}, nil, nil, NewSimpleAuthenticator(), &Config{})
conn.SetReadDeadline(time.Now().Add(time.Second))
b := make([]byte, 1024)
@ -44,10 +44,10 @@ func TestConnectionReadWrite(t *testing.T) {
auth := internet.NewAuthenticatorChain(srtp.SRTPFactory{}.Create(nil), NewSimpleAuthenticator())
connClient := NewConnection(1, upWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, auth)
connClient := NewConnection(1, upWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, auth, &Config{})
connClient.FetchInputFrom(downReader)
connServer := NewConnection(1, downWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, auth)
connServer := NewConnection(1, downWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, auth, &Config{})
connServer.FetchInputFrom(upReader)
totalWritten := 1024 * 1024

View File

@ -25,20 +25,32 @@ func DialKCP(src v2net.Address, dest v2net.Destination, options internet.DialerO
return nil, err
}
cpip, err := effectiveConfig.GetAuthenticator()
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
log.Error("KCP|Dialer: Failed to get KCP settings: ", err)
return nil, err
}
kcpSettings := networkSettings.(*Config)
cpip, err := kcpSettings.GetAuthenticator()
if err != nil {
log.Error("KCP|Dialer: Failed to create authenticator: ", err)
return nil, err
}
conv := uint16(atomic.AddUint32(&globalConv, 1))
session := NewConnection(conv, conn, conn.LocalAddr().(*net.UDPAddr), conn.RemoteAddr().(*net.UDPAddr), cpip)
session := NewConnection(conv, conn, conn.LocalAddr().(*net.UDPAddr), conn.RemoteAddr().(*net.UDPAddr), cpip, kcpSettings)
session.FetchInputFrom(conn)
var iConn internet.Connection
iConn = session
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS {
config := options.Stream.TLSSettings.GetTLSConfig()
if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("KCP|Dialer: Failed to apply TLS config: ", err)
return nil, err
}
config := securitySettings.(*v2tls.Config).GetTLSConfig()
if dest.Address.Family().IsDomain() {
config.ServerName = dest.Address.Domain()
}

View File

@ -12,12 +12,28 @@ import (
"v2ray.com/core/testing/assert"
"v2ray.com/core/transport/internet"
. "v2ray.com/core/transport/internet/kcp"
"github.com/golang/protobuf/ptypes"
)
func TestDialAndListen(t *testing.T) {
assert := assert.On(t)
listerner, err := NewListener(v2net.LocalHostIP, v2net.Port(0), internet.ListenOptions{})
kcpSettings := new(Config)
anySettings, err := ptypes.MarshalAny(kcpSettings)
assert.Error(err).IsNil()
listerner, err := NewListener(v2net.LocalHostIP, v2net.Port(0), internet.ListenOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_KCP,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_KCP,
Settings: anySettings,
},
},
},
})
assert.Error(err).IsNil()
port := v2net.Port(listerner.Addr().(*net.UDPAddr).Port)
@ -46,7 +62,17 @@ func TestDialAndListen(t *testing.T) {
wg := new(sync.WaitGroup)
for i := 0; i < 10; i++ {
clientConn, err := DialKCP(v2net.LocalHostIP, v2net.UDPDestination(v2net.LocalHostIP, port), internet.DialerOptions{})
clientConn, err := DialKCP(v2net.LocalHostIP, v2net.UDPDestination(v2net.LocalHostIP, port), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_KCP,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_KCP,
Settings: anySettings,
},
},
},
})
assert.Error(err).IsNil()
wg.Add(1)

View File

@ -25,10 +25,18 @@ type Listener struct {
awaitingConns chan *Connection
hub *udp.UDPHub
tlsConfig *tls.Config
config *Config
}
func NewListener(address v2net.Address, port v2net.Port, options internet.ListenOptions) (*Listener, error) {
auth, err := effectiveConfig.GetAuthenticator()
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
log.Error("KCP|Listener: Failed to get KCP settings: ", err)
return nil, err
}
kcpSettings := networkSettings.(*Config)
auth, err := kcpSettings.GetAuthenticator()
if err != nil {
return nil, err
}
@ -37,9 +45,15 @@ func NewListener(address v2net.Address, port v2net.Port, options internet.Listen
sessions: make(map[string]*Connection),
awaitingConns: make(chan *Connection, 64),
running: true,
config: kcpSettings,
}
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS {
l.tlsConfig = options.Stream.TLSSettings.GetTLSConfig()
if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("KCP|Listener: Failed to apply TLS config: ", err)
return nil, err
}
l.tlsConfig = securitySettings.(*v2tls.Config).GetTLSConfig()
}
hub, err := udp.ListenUDP(address, port, udp.ListenOption{Callback: l.OnReceive})
if err != nil {
@ -89,11 +103,11 @@ func (this *Listener) OnReceive(payload *alloc.Buffer, session *proxy.SessionInf
IP: src.Address.IP(),
Port: int(src.Port),
}
auth, err := effectiveConfig.GetAuthenticator()
auth, err := this.config.GetAuthenticator()
if err != nil {
log.Error("KCP|Listener: Failed to create authenticator: ", err)
}
conn = NewConnection(conv, writer, this.Addr().(*net.UDPAddr), srcAddr, auth)
conn = NewConnection(conv, writer, this.Addr().(*net.UDPAddr), srcAddr, auth, this.config)
select {
case this.awaitingConns <- conn:
case <-time.After(time.Second * 5):

View File

@ -62,6 +62,7 @@ func (this *BufferedSegmentWriter) Flush() {
type AuthenticationWriter struct {
Authenticator internet.Authenticator
Writer io.Writer
Config *Config
}
func (this *AuthenticationWriter) Write(payload *alloc.Buffer) error {
@ -75,5 +76,5 @@ func (this *AuthenticationWriter) Write(payload *alloc.Buffer) error {
func (this *AuthenticationWriter) Release() {}
func (this *AuthenticationWriter) Mtu() uint32 {
return effectiveConfig.Mtu.GetValue() - uint32(this.Authenticator.Overhead())
return this.Config.Mtu.GetValue() - uint32(this.Authenticator.Overhead())
}

View File

@ -124,8 +124,8 @@ type ReceivingWorker struct {
func NewReceivingWorker(kcp *Connection) *ReceivingWorker {
worker := &ReceivingWorker{
conn: kcp,
window: NewReceivingWindow(effectiveConfig.GetReceivingBufferSize()),
windowSize: effectiveConfig.GetReceivingInFlightSize(),
window: NewReceivingWindow(kcp.Config.GetReceivingBufferSize()),
windowSize: kcp.Config.GetReceivingInFlightSize(),
}
worker.acklist = NewAckList(worker)
return worker

View File

@ -185,9 +185,9 @@ func NewSendingWorker(kcp *Connection) *SendingWorker {
conn: kcp,
fastResend: 2,
remoteNextNumber: 32,
controlWindow: effectiveConfig.GetSendingInFlightSize(),
controlWindow: kcp.Config.GetSendingInFlightSize(),
}
worker.window = NewSendingWindow(effectiveConfig.GetSendingBufferSize(), worker, worker.OnPacketLoss)
worker.window = NewSendingWindow(kcp.Config.GetSendingBufferSize(), worker, worker.OnPacketLoss)
return worker
}
@ -291,7 +291,7 @@ func (this *SendingWorker) Write(seg Segment) {
}
func (this *SendingWorker) OnPacketLoss(lossRate uint32) {
if !effectiveConfig.Congestion || this.conn.roundTrip.Timeout() == 0 {
if !this.conn.Config.Congestion || this.conn.roundTrip.Timeout() == 0 {
return
}
@ -303,8 +303,8 @@ func (this *SendingWorker) OnPacketLoss(lossRate uint32) {
if this.controlWindow < 16 {
this.controlWindow = 16
}
if this.controlWindow > 2*effectiveConfig.GetSendingInFlightSize() {
this.controlWindow = 2 * effectiveConfig.GetSendingInFlightSize()
if this.controlWindow > 2*this.conn.Config.GetSendingInFlightSize() {
this.controlWindow = 2 * this.conn.Config.GetSendingInFlightSize()
}
}
@ -312,11 +312,11 @@ func (this *SendingWorker) Flush(current uint32) {
this.Lock()
defer this.Unlock()
cwnd := this.firstUnacknowledged + effectiveConfig.GetSendingInFlightSize()
cwnd := this.firstUnacknowledged + this.conn.Config.GetSendingInFlightSize()
if cwnd > this.remoteNextNumber {
cwnd = this.remoteNextNumber
}
if effectiveConfig.Congestion && cwnd > this.firstUnacknowledged+this.controlWindow {
if this.conn.Config.Congestion && cwnd > this.firstUnacknowledged+this.controlWindow {
cwnd = this.firstUnacknowledged + this.controlWindow
}

View File

@ -1,15 +1,14 @@
package tcp
type Config struct {
ConnectionReuse bool
}
import (
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
func (this *Config) Apply() {
effectiveConfig = this
}
var (
effectiveConfig = &Config{
ConnectionReuse: true,
}
"github.com/golang/protobuf/proto"
)
func init() {
internet.RegisterNetworkConfigCreator(v2net.Network_TCP, func() proto.Message {
return new(Config)
})
}

View File

@ -0,0 +1,58 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/tcp/config.proto
// DO NOT EDIT!
/*
Package tcp is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/internet/tcp/config.proto
It has these top-level messages:
Config
*/
package tcp
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// 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 Config struct {
ConnectionReuse bool `protobuf:"varint,1,opt,name=connection_reuse,json=connectionReuse" json:"connection_reuse,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{0} }
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.transport.internet.tcp.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/transport/internet/tcp/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 158 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x8e, 0xb1, 0x0a, 0xc2, 0x50,
0x0c, 0x45, 0x29, 0x42, 0x91, 0xe7, 0xa0, 0x74, 0x72, 0x54, 0x41, 0xd0, 0x25, 0x0f, 0xda, 0xc9,
0xb5, 0xfe, 0x80, 0x74, 0x74, 0x91, 0x1a, 0xa2, 0x74, 0x68, 0x12, 0xd2, 0x28, 0xf8, 0xf7, 0xd2,
0x4a, 0x75, 0x74, 0xbd, 0xdc, 0x73, 0x38, 0x21, 0x7f, 0xe6, 0x56, 0xbf, 0x00, 0xa5, 0x8d, 0x28,
0x46, 0xd1, 0xad, 0xe6, 0x4e, 0xc5, 0x3c, 0x36, 0xec, 0x64, 0x4c, 0x1e, 0x1d, 0x35, 0xa2, 0xf0,
0xad, 0xb9, 0x83, 0x9a, 0xb8, 0x64, 0xeb, 0x91, 0x31, 0x82, 0xef, 0x1f, 0xc6, 0x3f, 0x38, 0xea,
0xa6, 0x08, 0xe9, 0x71, 0x40, 0xb2, 0x7d, 0x58, 0xa0, 0x30, 0x13, 0x7a, 0x23, 0x7c, 0x31, 0x7a,
0x74, 0xb4, 0x4c, 0x56, 0xc9, 0x6e, 0x5a, 0xcd, 0x7f, 0x7b, 0xd5, 0xcf, 0xe5, 0x21, 0x6c, 0x51,
0x5a, 0xf8, 0x6b, 0x2f, 0x67, 0x1f, 0xf7, 0xa9, 0xaf, 0x39, 0x4f, 0x1c, 0xf5, 0x9a, 0x0e, 0x65,
0xc5, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x00, 0xa0, 0xa8, 0x3f, 0xcf, 0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,10 @@
syntax = "proto3";
package v2ray.core.transport.internet.tcp;
option go_package = "tcp";
option java_package = "com.v2ray.core.transport.internet.tcp";
option java_outer_classname = "ConfigProto";
message Config {
bool connection_reuse = 1;
}

View File

@ -31,14 +31,16 @@ type Connection struct {
conn net.Conn
listener ConnectionManager
reusable bool
config *Config
}
func NewConnection(dest string, conn net.Conn, manager ConnectionManager) *Connection {
func NewConnection(dest string, conn net.Conn, manager ConnectionManager, config *Config) *Connection {
return &Connection{
dest: dest,
conn: conn,
listener: manager,
reusable: effectiveConfig.ConnectionReuse,
reusable: config.ConnectionReuse,
config: config,
}
}
@ -91,7 +93,7 @@ func (this *Connection) SetWriteDeadline(t time.Time) error {
}
func (this *Connection) SetReusable(reusable bool) {
if !effectiveConfig.ConnectionReuse {
if !this.config.ConnectionReuse {
return
}
this.reusable = reusable

View File

@ -7,6 +7,7 @@ import (
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
)
var (
@ -18,9 +19,15 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
if src == nil {
src = v2net.AnyIP
}
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
tcpSettings := networkSettings.(*Config)
id := src.String() + "-" + dest.NetAddr()
var conn net.Conn
if dest.Network == v2net.Network_TCP && effectiveConfig.ConnectionReuse {
if dest.Network == v2net.Network_TCP && tcpSettings.ConnectionReuse {
conn = globalCache.Get(id)
}
if conn == nil {
@ -30,14 +37,19 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
return nil, err
}
}
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS {
config := options.Stream.TLSSettings.GetTLSConfig()
if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("TCP: Failed to apply TLS config: ", err)
return nil, err
}
config := securitySettings.(*v2tls.Config).GetTLSConfig()
if dest.Address.Family().IsDomain() {
config.ServerName = dest.Address.Domain()
}
conn = tls.Client(conn, config)
}
return NewConnection(id, conn, globalCache), nil
return NewConnection(id, conn, globalCache, tcpSettings), nil
}
func DialRaw(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) {

View File

@ -7,8 +7,10 @@ import (
"sync"
"time"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
)
var (
@ -26,6 +28,7 @@ type TCPListener struct {
listener *net.TCPListener
awaitingConns chan *ConnectionWithError
tlsConfig *tls.Config
config *Config
}
func ListenTCP(address v2net.Address, port v2net.Port, options internet.ListenOptions) (internet.Listener, error) {
@ -36,13 +39,25 @@ func ListenTCP(address v2net.Address, port v2net.Port, options internet.ListenOp
if err != nil {
return nil, err
}
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
tcpSettings := networkSettings.(*Config)
l := &TCPListener{
acccepting: true,
listener: listener,
awaitingConns: make(chan *ConnectionWithError, 32),
config: tcpSettings,
}
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS {
l.tlsConfig = options.Stream.TLSSettings.GetTLSConfig()
if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("TCP: Failed to apply TLS config: ", err)
return nil, err
}
l.tlsConfig = securitySettings.(*v2tls.Config).GetTLSConfig()
}
go l.KeepAccepting()
return l, nil
@ -62,7 +77,7 @@ func (this *TCPListener) Accept() (internet.Connection, error) {
if this.tlsConfig != nil {
conn = tls.Server(conn, this.tlsConfig)
}
return NewConnection("", conn, this), nil
return NewConnection("", conn, this, this.config), nil
case <-time.After(time.Second * 2):
}
}

View File

@ -20,7 +20,7 @@ var (
type ListenFunc func(address v2net.Address, port v2net.Port, options ListenOptions) (Listener, error)
type ListenOptions struct {
Stream *StreamSettings
Stream *StreamConfig
}
type Listener interface {
@ -36,23 +36,23 @@ type TCPHub struct {
accepting bool
}
func ListenTCP(address v2net.Address, port v2net.Port, callback ConnectionHandler, settings *StreamSettings) (*TCPHub, error) {
func ListenTCP(address v2net.Address, port v2net.Port, callback ConnectionHandler, settings *StreamConfig) (*TCPHub, error) {
var listener Listener
var err error
options := ListenOptions{
Stream: settings,
}
switch {
case settings.IsCapableOf(StreamConnectionTypeTCP):
switch settings.Network {
case v2net.Network_TCP:
listener, err = TCPListenFunc(address, port, options)
case settings.IsCapableOf(StreamConnectionTypeKCP):
case v2net.Network_KCP:
listener, err = KCPListenFunc(address, port, options)
case settings.IsCapableOf(StreamConnectionTypeWebSocket):
case v2net.Network_WebSocket:
listener, err = WSListenFunc(address, port, options)
case settings.IsCapableOf(StreamConnectionTypeRawTCP):
case v2net.Network_RawTCP:
listener, err = RawTCPListenFunc(address, port, options)
default:
log.Error("Internet|Listener: Unknown stream type: ", settings.Type)
log.Error("Internet|Listener: Unknown stream type: ", settings.Network)
err = ErrUnsupportedStreamType
}

View File

@ -0,0 +1,39 @@
package tls
import (
"crypto/tls"
"v2ray.com/core/common/log"
)
var (
globalSessionCache = tls.NewLRUClientSessionCache(128)
)
func (this *Config) BuildCertificates() []tls.Certificate {
certs := make([]tls.Certificate, 0, len(this.Certificate))
for _, entry := range this.Certificate {
keyPair, err := tls.X509KeyPair(entry.Certificate, entry.Key)
if err != nil {
log.Warning("TLS: ignoring invalid X509 key pair: ", err)
continue
}
certs = append(certs, keyPair)
}
return certs
}
func (this *Config) GetTLSConfig() *tls.Config {
config := &tls.Config{
ClientSessionCache: globalSessionCache,
}
if this == nil {
return config
}
config.InsecureSkipVerify = this.AllowInsecure
config.Certificates = this.BuildCertificates()
config.BuildNameToCertificate()
return config
}

View File

@ -0,0 +1,82 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/tls/config.proto
// DO NOT EDIT!
/*
Package tls is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/internet/tls/config.proto
It has these top-level messages:
Certificate
Config
*/
package tls
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// 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 Certificate struct {
Certificate []byte `protobuf:"bytes,1,opt,name=Certificate,json=certificate,proto3" json:"Certificate,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=Key,json=key,proto3" json:"Key,omitempty"`
}
func (m *Certificate) Reset() { *m = Certificate{} }
func (m *Certificate) String() string { return proto.CompactTextString(m) }
func (*Certificate) ProtoMessage() {}
func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type Config struct {
AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure" json:"allow_insecure,omitempty"`
Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate" json:"certificate,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{1} }
func (m *Config) GetCertificate() []*Certificate {
if m != nil {
return m.Certificate
}
return nil
}
func init() {
proto.RegisterType((*Certificate)(nil), "v2ray.core.transport.internet.tls.Certificate")
proto.RegisterType((*Config)(nil), "v2ray.core.transport.internet.tls.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/transport/internet/tls/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 219 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x90, 0xb1, 0x4b, 0x43, 0x31,
0x10, 0xc6, 0x79, 0x0d, 0x14, 0x49, 0x54, 0x24, 0xd3, 0x1b, 0x9f, 0x85, 0x42, 0xa7, 0x0b, 0x3c,
0x27, 0x47, 0xdb, 0x49, 0x5c, 0x4a, 0x47, 0x17, 0x89, 0xe1, 0x2a, 0xc1, 0x34, 0x57, 0x2e, 0xa7,
0xf2, 0x46, 0xff, 0x73, 0x31, 0xb5, 0xf2, 0x3a, 0x75, 0xbc, 0xef, 0xbe, 0xfb, 0xee, 0xc7, 0xa7,
0xfb, 0xcf, 0x9e, 0xfd, 0x00, 0x81, 0x76, 0x2e, 0x10, 0xa3, 0x13, 0xf6, 0xb9, 0xec, 0x89, 0xc5,
0xc5, 0x2c, 0xc8, 0x19, 0xc5, 0x49, 0x2a, 0x2e, 0x50, 0xde, 0xc6, 0x37, 0xd8, 0x33, 0x09, 0xd9,
0xdb, 0xe3, 0x0d, 0x23, 0xfc, 0xfb, 0xe1, 0xe8, 0x07, 0x49, 0x65, 0xf6, 0xa0, 0xcd, 0x0a, 0x59,
0xe2, 0x36, 0x06, 0x2f, 0x68, 0xbb, 0x93, 0xb1, 0x6d, 0xba, 0x66, 0x71, 0xb9, 0x31, 0x61, 0xe4,
0xb8, 0xd1, 0xea, 0x09, 0x87, 0x76, 0x52, 0x37, 0xea, 0x1d, 0x87, 0xd9, 0x77, 0xa3, 0xa7, 0xab,
0xfa, 0xd6, 0xce, 0xf5, 0xb5, 0x4f, 0x89, 0xbe, 0x5e, 0x62, 0x2e, 0x18, 0x3e, 0xf8, 0x90, 0x70,
0xb1, 0xb9, 0xaa, 0xea, 0xe3, 0x9f, 0x68, 0xd7, 0x7a, 0x1c, 0xd9, 0x4e, 0x3a, 0xb5, 0x30, 0x3d,
0xc0, 0x59, 0x5a, 0x18, 0xb1, 0x9d, 0x50, 0x2d, 0xef, 0xf5, 0x3c, 0xd0, 0xee, 0x7c, 0xc2, 0xd2,
0x1c, 0x48, 0xd7, 0xbf, 0xfd, 0x3c, 0x2b, 0x49, 0xe5, 0x75, 0x5a, 0xbb, 0xba, 0xfb, 0x09, 0x00,
0x00, 0xff, 0xff, 0xbb, 0x82, 0x9d, 0x49, 0x61, 0x01, 0x00, 0x00,
}

View File

@ -0,0 +1,16 @@
syntax = "proto3";
package v2ray.core.transport.internet.tls;
option go_package = "tls";
option java_package = "com.v2ray.core.transport.internet.tls";
option java_outer_classname = "ConfigProto";
message Certificate {
bytes Certificate = 1;
bytes Key = 2;
}
message Config {
bool allow_insecure = 1;
repeated Certificate certificate = 2;
}

View File

@ -0,0 +1,41 @@
// +build json
package tls
import (
"encoding/json"
"errors"
"io/ioutil"
)
func (this *Config) UnmarshalJSON(data []byte) error {
type JSONCertConfig struct {
CertFile string `json:"certificateFile"`
KeyFile string `json:"keyFile"`
}
type JSONConfig struct {
Insecure bool `json:"allowInsecure"`
Certs []*JSONCertConfig `json:"certificates"`
}
jsonConfig := new(JSONConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil {
return err
}
this.Certificate = make([]*Certificate, len(jsonConfig.Certs))
for idx, certConf := range jsonConfig.Certs {
cert, err := ioutil.ReadFile(certConf.CertFile)
if err != nil {
return errors.New("TLS: Failed to load certificate file: " + err.Error())
}
key, err := ioutil.ReadFile(certConf.KeyFile)
if err != nil {
return errors.New("TLS: Failed to load key file: " + err.Error())
}
this.Certificate[idx] = &Certificate{
Key: key,
Certificate: cert,
}
}
this.AllowInsecure = jsonConfig.Insecure
return nil
}

View File

@ -1,17 +1,14 @@
package ws
type Config struct {
ConnectionReuse bool
Path string
}
import (
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
func (this *Config) Apply() {
effectiveConfig = this
}
var (
effectiveConfig = &Config{
ConnectionReuse: true,
Path: "",
}
"github.com/golang/protobuf/proto"
)
func init() {
internet.RegisterNetworkConfigCreator(v2net.Network_WebSocket, func() proto.Message {
return new(Config)
})
}

View File

@ -0,0 +1,60 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/ws/config.proto
// DO NOT EDIT!
/*
Package ws is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/internet/ws/config.proto
It has these top-level messages:
Config
*/
package ws
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// 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 Config struct {
ConnectionReuse bool `protobuf:"varint,1,opt,name=connection_reuse,json=connectionReuse" json:"connection_reuse,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path" json:"path,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{0} }
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.transport.internet.ws.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/transport/internet/ws/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 174 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x32, 0x2c, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x29, 0x4a, 0xcc, 0x2b,
0x2e, 0xc8, 0x2f, 0x2a, 0xd1, 0xcf, 0xcc, 0x2b, 0x49, 0x2d, 0xca, 0x4b, 0x2d, 0xd1, 0x2f, 0x2f,
0xd6, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x52, 0x80,
0x69, 0x29, 0x4a, 0xd5, 0x83, 0x2b, 0xd7, 0x83, 0x29, 0xd7, 0x2b, 0x2f, 0x56, 0x72, 0xe7, 0x62,
0x73, 0x06, 0xeb, 0x10, 0xd2, 0xe4, 0x12, 0x48, 0xce, 0xcf, 0xcb, 0x4b, 0x4d, 0x2e, 0xc9, 0xcc,
0xcf, 0x8b, 0x2f, 0x4a, 0x2d, 0x2d, 0x4e, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x08, 0xe2, 0x47,
0x88, 0x07, 0x81, 0x84, 0x85, 0x84, 0xb8, 0x58, 0x0a, 0x12, 0x4b, 0x32, 0x24, 0x98, 0x14, 0x18,
0x35, 0x38, 0x83, 0xc0, 0x6c, 0x27, 0x73, 0x2e, 0x95, 0xe4, 0xfc, 0x5c, 0x3d, 0x42, 0x16, 0x3a,
0x71, 0x43, 0xac, 0x0b, 0x00, 0xb9, 0x2f, 0x8a, 0xa9, 0xbc, 0x38, 0x89, 0x0d, 0xec, 0x54, 0x63,
0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf1, 0x69, 0xf5, 0xaf, 0xdf, 0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,11 @@
syntax = "proto3";
package v2ray.core.transport.internet.ws;
option go_package = "ws";
option java_package = "com.v2ray.core.transport.internet.ws";
option java_outer_classname = "ConfigProto";
message Config {
bool connection_reuse = 1;
string path = 2;
}

View File

@ -20,14 +20,16 @@ type Connection struct {
conn *wsconn
listener ConnectionManager
reusable bool
config *Config
}
func NewConnection(dest string, conn *wsconn, manager ConnectionManager) *Connection {
func NewConnection(dest string, conn *wsconn, manager ConnectionManager, config *Config) *Connection {
return &Connection{
dest: dest,
conn: conn,
listener: manager,
reusable: effectiveConfig.ConnectionReuse,
reusable: config.ConnectionReuse,
config: config,
}
}
@ -80,7 +82,7 @@ func (this *Connection) SetWriteDeadline(t time.Time) error {
}
func (this *Connection) SetReusable(reusable bool) {
if !effectiveConfig.ConnectionReuse {
if !this.config.ConnectionReuse {
return
}
this.reusable = reusable

View File

@ -9,6 +9,7 @@ import (
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
)
var (
@ -20,9 +21,15 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
if src == nil {
src = v2net.AnyIP
}
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
wsSettings := networkSettings.(*Config)
id := src.String() + "-" + dest.NetAddr()
var conn *wsconn
if dest.Network == v2net.Network_TCP && effectiveConfig.ConnectionReuse {
if dest.Network == v2net.Network_TCP && wsSettings.ConnectionReuse {
connt := globalCache.Get(id)
if connt != nil {
conn = connt.(*wsconn)
@ -36,7 +43,7 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
return nil, err
}
}
return NewConnection(id, conn, globalCache), nil
return NewConnection(id, conn, globalCache, wsSettings), nil
}
func init() {
@ -44,6 +51,12 @@ func init() {
}
func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (*wsconn, error) {
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
wsSettings := networkSettings.(*Config)
commonDial := func(network, addr string) (net.Conn, error) {
return internet.DialToDest(src, dest)
}
@ -56,9 +69,14 @@ func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOp
protocol := "ws"
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS {
if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
protocol = "wss"
dialer.TLSClientConfig = options.Stream.TLSSettings.GetTLSConfig()
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("WebSocket: Failed to create apply TLS config: ", err)
return nil, err
}
dialer.TLSClientConfig = securitySettings.(*v2tls.Config).GetTLSConfig()
if dest.Address.Family().IsDomain() {
dialer.TLSClientConfig.ServerName = dest.Address.Domain()
}
@ -66,7 +84,7 @@ func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOp
uri := func(dst v2net.Destination, pto string, path string) string {
return fmt.Sprintf("%v://%v/%v", pto, dst.NetAddr(), path)
}(dest, protocol, effectiveConfig.Path)
}(dest, protocol, wsSettings.Path)
conn, resp, err := dialer.Dial(uri, nil)
if err != nil {
@ -77,7 +95,11 @@ func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOp
return nil, err
}
return func() internet.Connection {
connv2ray := &wsconn{wsc: conn, connClosing: false}
connv2ray := &wsconn{
wsc: conn,
connClosing: false,
config: wsSettings,
}
connv2ray.setup()
return connv2ray
}().(*wsconn), nil

View File

@ -13,6 +13,7 @@ import (
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
)
var (
@ -30,26 +31,37 @@ type WSListener struct {
awaitingConns chan *ConnectionWithError
listener *StoppableListener
tlsConfig *tls.Config
config *Config
}
func ListenWS(address v2net.Address, port v2net.Port, options internet.ListenOptions) (internet.Listener, error) {
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
wsSettings := networkSettings.(*Config)
l := &WSListener{
acccepting: true,
awaitingConns: make(chan *ConnectionWithError, 32),
config: wsSettings,
}
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS {
l.tlsConfig = options.Stream.TLSSettings.GetTLSConfig()
if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("WebSocket: Failed to create apply TLS config: ", err)
return nil, err
}
l.tlsConfig = securitySettings.(*v2tls.Config).GetTLSConfig()
}
err := l.listenws(address, port)
err = l.listenws(address, port)
return l, err
}
func (wsl *WSListener) listenws(address v2net.Address, port v2net.Port) error {
http.HandleFunc("/"+effectiveConfig.Path, func(w http.ResponseWriter, r *http.Request) {
http.HandleFunc("/"+wsl.config.Path, func(w http.ResponseWriter, r *http.Request) {
con, err := wsl.converttovws(w, r)
if err != nil {
log.Warning("WebSocket|Listener: Failed to convert connection: ", err)
@ -140,7 +152,7 @@ func (this *WSListener) Accept() (internet.Connection, error) {
if connErr.err != nil {
return nil, connErr.err
}
return NewConnection("", connErr.conn.(*wsconn), this), nil
return NewConnection("", connErr.conn.(*wsconn), this, this.config), nil
case <-time.After(time.Second * 2):
}
}

View File

@ -1,20 +1,43 @@
package ws_test
import (
"crypto/tls"
"io/ioutil"
"testing"
"time"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/testing/assert"
"v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
. "v2ray.com/core/transport/internet/ws"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/any"
)
func MarshalSettings(config *Config, assert *assert.Assert) *any.Any {
anySettings, err := ptypes.MarshalAny(config)
assert.Error(err).IsNil()
return anySettings
}
func Test_Connect_ws(t *testing.T) {
assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 80), internet.DialerOptions{})
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 80), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
},
})
assert.Error(err).IsNil()
conn.Write([]byte("echo"))
s := make(chan int)
@ -33,10 +56,18 @@ func Test_Connect_ws(t *testing.T) {
func Test_Connect_wss(t *testing.T) {
assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{
Security: internet.StreamSecurityTypeTLS,
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
},
})
assert.Error(err).IsNil()
@ -57,10 +88,18 @@ func Test_Connect_wss(t *testing.T) {
func Test_Connect_wss_1_nil(t *testing.T) {
assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(nil, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{
Security: internet.StreamSecurityTypeTLS,
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
},
})
assert.Error(err).IsNil()
@ -81,8 +120,19 @@ func Test_Connect_wss_1_nil(t *testing.T) {
func Test_Connect_ws_guess(t *testing.T) {
assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 80), internet.DialerOptions{})
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 80), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
},
})
assert.Error(err).IsNil()
conn.Write([]byte("echo"))
s := make(chan int)
@ -101,10 +151,18 @@ func Test_Connect_ws_guess(t *testing.T) {
func Test_Connect_wss_guess(t *testing.T) {
assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{
Security: internet.StreamSecurityTypeTLS,
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
},
})
assert.Error(err).IsNil()
@ -125,10 +183,18 @@ func Test_Connect_wss_guess(t *testing.T) {
func Test_Connect_wss_guess_fail(t *testing.T) {
assert := assert.On(t)
(&Config{Path: ""}).Apply()
_, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("static.kkdev.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{
Security: internet.StreamSecurityTypeTLS,
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
},
})
assert.Error(err).IsNotNil()
@ -136,12 +202,21 @@ func Test_Connect_wss_guess_fail(t *testing.T) {
func Test_Connect_wss_guess_reuse(t *testing.T) {
assert := assert.On(t)
(&Config{Path: "", ConnectionReuse: true}).Apply()
i := 3
for i != 0 {
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{
Security: internet.StreamSecurityTypeTLS,
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
ConnectionReuse: true,
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
},
})
assert.Error(err).IsNil()
@ -170,8 +245,19 @@ func Test_Connect_wss_guess_reuse(t *testing.T) {
func Test_listenWSAndDial(t *testing.T) {
assert := assert.On(t)
(&Config{Path: "ws"}).Apply()
listen, err := ListenWS(v2net.DomainAddress("localhost"), 13142, internet.ListenOptions{})
listen, err := ListenWS(v2net.DomainAddress("localhost"), 13142, internet.ListenOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "ws",
}, assert),
},
},
},
})
assert.Error(err).IsNil()
go func() {
conn, err := listen.Accept()
@ -185,15 +271,51 @@ func Test_listenWSAndDial(t *testing.T) {
conn.Close()
listen.Close()
}()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{})
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "ws",
}, assert),
},
},
},
})
assert.Error(err).IsNil()
conn.Close()
<-time.After(time.Second * 5)
conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{})
conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "ws",
}, assert),
},
},
},
})
assert.Error(err).IsNil()
conn.Close()
<-time.After(time.Second * 15)
conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{})
conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "ws",
}, assert),
},
},
},
})
assert.Error(err).IsNil()
conn.Close()
}
@ -204,14 +326,34 @@ func Test_listenWSAndDial_TLS(t *testing.T) {
<-time.After(time.Second * 5)
assert.Fail("Too slow")
}()
(&Config{Path: "wss", ConnectionReuse: true}).Apply()
tlsSettings := &v2tls.Config{
AllowInsecure: true,
Certificate: []*v2tls.Certificate{
{
Certificate: ReadFile("./../../../testing/tls/cert.pem", assert),
Key: ReadFile("./../../../testing/tls/key.pem", assert),
},
},
}
anyTlsSettings, err := ptypes.MarshalAny(tlsSettings)
assert.Error(err).IsNil()
listen, err := ListenWS(v2net.DomainAddress("localhost"), 13143, internet.ListenOptions{
Stream: &internet.StreamSettings{
Security: internet.StreamSecurityTypeTLS,
TLSSettings: &internet.TLSSettings{
AllowInsecure: true,
Certs: LoadTestCert(assert),
Stream: &internet.StreamConfig{
SecurityType: internet.SecurityType_TLS,
SecuritySettings: []*internet.SecuritySettings{{
Type: internet.SecurityType_TLS,
Settings: anyTlsSettings,
}},
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "wss",
ConnectionReuse: true,
}, assert),
},
},
},
})
@ -223,11 +365,21 @@ func Test_listenWSAndDial_TLS(t *testing.T) {
listen.Close()
}()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13143), internet.DialerOptions{
Stream: &internet.StreamSettings{
Security: internet.StreamSecurityTypeTLS,
TLSSettings: &internet.TLSSettings{
AllowInsecure: true,
Certs: LoadTestCert(assert),
Stream: &internet.StreamConfig{
SecurityType: internet.SecurityType_TLS,
SecuritySettings: []*internet.SecuritySettings{{
Type: internet.SecurityType_TLS,
Settings: anyTlsSettings,
}},
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "wss",
ConnectionReuse: true,
}, assert),
},
},
},
})
@ -235,8 +387,8 @@ func Test_listenWSAndDial_TLS(t *testing.T) {
conn.Close()
}
func LoadTestCert(assert *assert.Assert) []tls.Certificate {
cert, err := tls.LoadX509KeyPair("./../../../testing/tls/cert.pem", "./../../../testing/tls/key.pem")
func ReadFile(file string, assert *assert.Assert) []byte {
b, err := ioutil.ReadFile(file)
assert.Error(err).IsNil()
return []tls.Certificate{cert}
return b
}

View File

@ -18,6 +18,7 @@ type wsconn struct {
reusable bool
rlock *sync.Mutex
wlock *sync.Mutex
config *Config
}
func (ws *wsconn) Read(b []byte) (n int, err error) {
@ -164,7 +165,7 @@ func (ws *wsconn) Reusable() bool {
}
func (ws *wsconn) SetReusable(reusable bool) {
if !effectiveConfig.ConnectionReuse {
if !ws.config.ConnectionReuse {
return
}
ws.reusable = reusable