mirror of
				https://github.com/optim-enterprises-bv/Xray-core.git
				synced 2025-11-03 20:17:53 +00:00 
			
		
		
		
	Add gRPC Transport support (#356)
Co-authored-by: JimhHan <50871214+JimhHan@users.noreply.github.com>
This commit is contained in:
		@@ -31,6 +31,22 @@ func New() *Buffer {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewExisted(b []byte) *Buffer {
 | 
			
		||||
	if cap(b) < Size {
 | 
			
		||||
		panic("Invalid buffer")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	oLen := len(b)
 | 
			
		||||
	if oLen < Size {
 | 
			
		||||
		b = append(b, make([]byte, Size-oLen)...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Buffer{
 | 
			
		||||
		v:   b,
 | 
			
		||||
		end: int32(oLen),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StackNew creates a new Buffer object on stack.
 | 
			
		||||
// This method is for buffers that is released in the same function.
 | 
			
		||||
func StackNew() Buffer {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								infra/conf/grpc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								infra/conf/grpc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
package conf
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/golang/protobuf/proto"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/grpc"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GRPCConfig struct {
 | 
			
		||||
	ServiceName string `json:"serviceName"`
 | 
			
		||||
	MultiMode   bool   `json:"multiMode"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g GRPCConfig) Build() (proto.Message, error) {
 | 
			
		||||
	return &grpc.Config{ServiceName: g.ServiceName, MultiMode: g.MultiMode}, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -13,6 +13,8 @@ type TransportConfig struct {
 | 
			
		||||
	HTTPConfig *HTTPConfig         `json:"httpSettings"`
 | 
			
		||||
	DSConfig   *DomainSocketConfig `json:"dsSettings"`
 | 
			
		||||
	QUICConfig *QUICConfig         `json:"quicSettings"`
 | 
			
		||||
	GRPCConfig *GRPCConfig         `json:"grpcSettings"`
 | 
			
		||||
	GUNConfig  *GRPCConfig         `json:"gunSettings"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Build implements Buildable.
 | 
			
		||||
@@ -85,5 +87,19 @@ func (c *TransportConfig) Build() (*global.Config, error) {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.GRPCConfig == nil {
 | 
			
		||||
		c.GRPCConfig = c.GUNConfig
 | 
			
		||||
	}
 | 
			
		||||
	if c.GRPCConfig != nil {
 | 
			
		||||
		gs, err := c.GRPCConfig.Build()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, newError("Failed to build gRPC config.").Base(err)
 | 
			
		||||
		}
 | 
			
		||||
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
			
		||||
			ProtocolName: "grpc",
 | 
			
		||||
			Settings:     serial.ToTypedMessage(gs),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return config, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -458,6 +458,8 @@ func (p TransportProtocol) Build() (string, error) {
 | 
			
		||||
		return "domainsocket", nil
 | 
			
		||||
	case "quic":
 | 
			
		||||
		return "quic", nil
 | 
			
		||||
	case "grpc", "gun":
 | 
			
		||||
		return "grpc", nil
 | 
			
		||||
	default:
 | 
			
		||||
		return "", newError("Config: unknown transport protocol: ", p)
 | 
			
		||||
	}
 | 
			
		||||
@@ -534,6 +536,8 @@ type StreamConfig struct {
 | 
			
		||||
	DSSettings     *DomainSocketConfig `json:"dsSettings"`
 | 
			
		||||
	QUICSettings   *QUICConfig         `json:"quicSettings"`
 | 
			
		||||
	SocketSettings *SocketConfig       `json:"sockopt"`
 | 
			
		||||
	GRPCConfig     *GRPCConfig         `json:"grpcSettings"`
 | 
			
		||||
	GUNConfig      *GRPCConfig         `json:"gunSettings"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Build implements Buildable.
 | 
			
		||||
@@ -643,6 +647,19 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
 | 
			
		||||
			Settings:     serial.ToTypedMessage(qs),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if c.GRPCConfig == nil {
 | 
			
		||||
		c.GRPCConfig = c.GUNConfig
 | 
			
		||||
	}
 | 
			
		||||
	if c.GRPCConfig != nil {
 | 
			
		||||
		gs, err := c.GRPCConfig.Build()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, newError("Failed to build gRPC config.").Base(err)
 | 
			
		||||
		}
 | 
			
		||||
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
			
		||||
			ProtocolName: "grpc",
 | 
			
		||||
			Settings:     serial.ToTypedMessage(gs),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if c.SocketSettings != nil {
 | 
			
		||||
		ss, err := c.SocketSettings.Build()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import (
 | 
			
		||||
	. "github.com/xtls/xray-core/infra/conf"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/global"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/grpc"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/http"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/noop"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/tls"
 | 
			
		||||
@@ -120,6 +121,10 @@ func TestTransportConfig(t *testing.T) {
 | 
			
		||||
					"header": {
 | 
			
		||||
						"type": "dtls"
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"grpcSettings": {
 | 
			
		||||
					"serviceName": "name",
 | 
			
		||||
					"multiMode": true
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
			Parser: createParser(),
 | 
			
		||||
@@ -190,6 +195,31 @@ func TestTransportConfig(t *testing.T) {
 | 
			
		||||
							Header: serial.ToTypedMessage(&tls.PacketConfig{}),
 | 
			
		||||
						}),
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						ProtocolName: "grpc",
 | 
			
		||||
						Settings: serial.ToTypedMessage(&grpc.Config{
 | 
			
		||||
							ServiceName: "name",
 | 
			
		||||
							MultiMode:   true,
 | 
			
		||||
						}),
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Input: `{
 | 
			
		||||
				"gunSettings": {
 | 
			
		||||
					"serviceName": "name"
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
			Parser: createParser(),
 | 
			
		||||
			Output: &global.Config{
 | 
			
		||||
				TransportSettings: []*internet.TransportConfig{
 | 
			
		||||
					{
 | 
			
		||||
						ProtocolName: "grpc",
 | 
			
		||||
						Settings: serial.ToTypedMessage(&grpc.Config{
 | 
			
		||||
							ServiceName: "name",
 | 
			
		||||
						}),
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	// Transports
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/domainsocket"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/grpc"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/http"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/kcp"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/quic"
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ import (
 | 
			
		||||
	"github.com/xtls/xray-core/testing/servers/tcp"
 | 
			
		||||
	"github.com/xtls/xray-core/testing/servers/udp"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/grpc"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/http"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/tls"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/websocket"
 | 
			
		||||
@@ -589,3 +590,239 @@ func TestHTTP2(t *testing.T) {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGRPC(t *testing.T) {
 | 
			
		||||
	tcpServer := tcp.Server{
 | 
			
		||||
		MsgProcessor: xor,
 | 
			
		||||
	}
 | 
			
		||||
	dest, err := tcpServer.Start()
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
	defer tcpServer.Close()
 | 
			
		||||
 | 
			
		||||
	userID := protocol.NewID(uuid.New())
 | 
			
		||||
	serverPort := tcp.PickPort()
 | 
			
		||||
	serverConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
 | 
			
		||||
					PortRange: net.SinglePortRange(serverPort),
 | 
			
		||||
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
					StreamSettings: &internet.StreamConfig{
 | 
			
		||||
						ProtocolName: "grpc",
 | 
			
		||||
						TransportSettings: []*internet.TransportConfig{
 | 
			
		||||
							{
 | 
			
		||||
								ProtocolName: "grpc",
 | 
			
		||||
								Settings:     serial.ToTypedMessage(&grpc.Config{ServiceName: "🍉"}),
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
						SecurityType: serial.GetMessageType(&tls.Config{}),
 | 
			
		||||
						SecuritySettings: []*serial.TypedMessage{
 | 
			
		||||
							serial.ToTypedMessage(&tls.Config{
 | 
			
		||||
								Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
 | 
			
		||||
							}),
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&inbound.Config{
 | 
			
		||||
					User: []*protocol.User{
 | 
			
		||||
						{
 | 
			
		||||
							Account: serial.ToTypedMessage(&vmess.Account{
 | 
			
		||||
								Id: userID.String(),
 | 
			
		||||
							}),
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientPort := tcp.PickPort()
 | 
			
		||||
	clientConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
 | 
			
		||||
					PortRange: net.SinglePortRange(clientPort),
 | 
			
		||||
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
				}),
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
 | 
			
		||||
					Address: net.NewIPOrDomain(dest.Address),
 | 
			
		||||
					Port:    uint32(dest.Port),
 | 
			
		||||
					NetworkList: &net.NetworkList{
 | 
			
		||||
						Network: []net.Network{net.Network_TCP},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&outbound.Config{
 | 
			
		||||
					Receiver: []*protocol.ServerEndpoint{
 | 
			
		||||
						{
 | 
			
		||||
							Address: net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
							Port:    uint32(serverPort),
 | 
			
		||||
							User: []*protocol.User{
 | 
			
		||||
								{
 | 
			
		||||
									Account: serial.ToTypedMessage(&vmess.Account{
 | 
			
		||||
										Id: userID.String(),
 | 
			
		||||
									}),
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
				SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
 | 
			
		||||
					StreamSettings: &internet.StreamConfig{
 | 
			
		||||
						ProtocolName: "grpc",
 | 
			
		||||
						TransportSettings: []*internet.TransportConfig{
 | 
			
		||||
							{
 | 
			
		||||
								ProtocolName: "grpc",
 | 
			
		||||
								Settings:     serial.ToTypedMessage(&grpc.Config{ServiceName: "🍉"}),
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
						SecurityType: serial.GetMessageType(&tls.Config{}),
 | 
			
		||||
						SecuritySettings: []*serial.TypedMessage{
 | 
			
		||||
							serial.ToTypedMessage(&tls.Config{
 | 
			
		||||
								AllowInsecure: true,
 | 
			
		||||
							}),
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	servers, err := InitializeServerConfigs(serverConfig, clientConfig)
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
	defer CloseAllServers(servers)
 | 
			
		||||
 | 
			
		||||
	var errg errgroup.Group
 | 
			
		||||
	for i := 0; i < 10; i++ {
 | 
			
		||||
		errg.Go(testTCPConn(clientPort, 1024*10240, time.Second*40))
 | 
			
		||||
	}
 | 
			
		||||
	if err := errg.Wait(); err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGRPCMultiMode(t *testing.T) {
 | 
			
		||||
	tcpServer := tcp.Server{
 | 
			
		||||
		MsgProcessor: xor,
 | 
			
		||||
	}
 | 
			
		||||
	dest, err := tcpServer.Start()
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
	defer tcpServer.Close()
 | 
			
		||||
 | 
			
		||||
	userID := protocol.NewID(uuid.New())
 | 
			
		||||
	serverPort := tcp.PickPort()
 | 
			
		||||
	serverConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
 | 
			
		||||
					PortRange: net.SinglePortRange(serverPort),
 | 
			
		||||
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
					StreamSettings: &internet.StreamConfig{
 | 
			
		||||
						ProtocolName: "grpc",
 | 
			
		||||
						TransportSettings: []*internet.TransportConfig{
 | 
			
		||||
							{
 | 
			
		||||
								ProtocolName: "grpc",
 | 
			
		||||
								Settings:     serial.ToTypedMessage(&grpc.Config{ServiceName: "🍉"}),
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
						SecurityType: serial.GetMessageType(&tls.Config{}),
 | 
			
		||||
						SecuritySettings: []*serial.TypedMessage{
 | 
			
		||||
							serial.ToTypedMessage(&tls.Config{
 | 
			
		||||
								Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
 | 
			
		||||
							}),
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&inbound.Config{
 | 
			
		||||
					User: []*protocol.User{
 | 
			
		||||
						{
 | 
			
		||||
							Account: serial.ToTypedMessage(&vmess.Account{
 | 
			
		||||
								Id: userID.String(),
 | 
			
		||||
							}),
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientPort := tcp.PickPort()
 | 
			
		||||
	clientConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
 | 
			
		||||
					PortRange: net.SinglePortRange(clientPort),
 | 
			
		||||
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
				}),
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
 | 
			
		||||
					Address: net.NewIPOrDomain(dest.Address),
 | 
			
		||||
					Port:    uint32(dest.Port),
 | 
			
		||||
					NetworkList: &net.NetworkList{
 | 
			
		||||
						Network: []net.Network{net.Network_TCP},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&outbound.Config{
 | 
			
		||||
					Receiver: []*protocol.ServerEndpoint{
 | 
			
		||||
						{
 | 
			
		||||
							Address: net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
							Port:    uint32(serverPort),
 | 
			
		||||
							User: []*protocol.User{
 | 
			
		||||
								{
 | 
			
		||||
									Account: serial.ToTypedMessage(&vmess.Account{
 | 
			
		||||
										Id: userID.String(),
 | 
			
		||||
									}),
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
				SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
 | 
			
		||||
					StreamSettings: &internet.StreamConfig{
 | 
			
		||||
						ProtocolName: "grpc",
 | 
			
		||||
						TransportSettings: []*internet.TransportConfig{
 | 
			
		||||
							{
 | 
			
		||||
								ProtocolName: "grpc",
 | 
			
		||||
								Settings:     serial.ToTypedMessage(&grpc.Config{ServiceName: "🍉", MultiMode: true}),
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
						SecurityType: serial.GetMessageType(&tls.Config{}),
 | 
			
		||||
						SecuritySettings: []*serial.TypedMessage{
 | 
			
		||||
							serial.ToTypedMessage(&tls.Config{
 | 
			
		||||
								AllowInsecure: true,
 | 
			
		||||
							}),
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	servers, err := InitializeServerConfigs(serverConfig, clientConfig)
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
	defer CloseAllServers(servers)
 | 
			
		||||
 | 
			
		||||
	var errg errgroup.Group
 | 
			
		||||
	for i := 0; i < 10; i++ {
 | 
			
		||||
		errg.Go(testTCPConn(clientPort, 1024*10240, time.Second*40))
 | 
			
		||||
	}
 | 
			
		||||
	if err := errg.Wait(); err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								transport/internet/grpc/config.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								transport/internet/grpc/config.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
package grpc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const protocolName = "grpc"
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
 | 
			
		||||
		return new(Config)
 | 
			
		||||
	}))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										172
									
								
								transport/internet/grpc/config.pb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								transport/internet/grpc/config.pb.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
			
		||||
// versions:
 | 
			
		||||
// 	protoc-gen-go v1.25.0
 | 
			
		||||
// 	protoc        v3.15.6
 | 
			
		||||
// source: transport/internet/grpc/config.proto
 | 
			
		||||
 | 
			
		||||
package grpc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	proto "github.com/golang/protobuf/proto"
 | 
			
		||||
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 | 
			
		||||
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 | 
			
		||||
	reflect "reflect"
 | 
			
		||||
	sync "sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Verify that this generated code is sufficiently up-to-date.
 | 
			
		||||
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
 | 
			
		||||
	// Verify that runtime/protoimpl is sufficiently up-to-date.
 | 
			
		||||
	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This is a compile-time assertion that a sufficiently up-to-date version
 | 
			
		||||
// of the legacy proto package is being used.
 | 
			
		||||
const _ = proto.ProtoPackageIsVersion4
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	state         protoimpl.MessageState
 | 
			
		||||
	sizeCache     protoimpl.SizeCache
 | 
			
		||||
	unknownFields protoimpl.UnknownFields
 | 
			
		||||
 | 
			
		||||
	Host        string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
 | 
			
		||||
	ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
 | 
			
		||||
	MultiMode   bool   `protobuf:"varint,3,opt,name=multi_mode,json=multiMode,proto3" json:"multi_mode,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) Reset() {
 | 
			
		||||
	*x = Config{}
 | 
			
		||||
	if protoimpl.UnsafeEnabled {
 | 
			
		||||
		mi := &file_transport_internet_grpc_config_proto_msgTypes[0]
 | 
			
		||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
			
		||||
		ms.StoreMessageInfo(mi)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) String() string {
 | 
			
		||||
	return protoimpl.X.MessageStringOf(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*Config) ProtoMessage() {}
 | 
			
		||||
 | 
			
		||||
func (x *Config) ProtoReflect() protoreflect.Message {
 | 
			
		||||
	mi := &file_transport_internet_grpc_config_proto_msgTypes[0]
 | 
			
		||||
	if protoimpl.UnsafeEnabled && x != nil {
 | 
			
		||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
			
		||||
		if ms.LoadMessageInfo() == nil {
 | 
			
		||||
			ms.StoreMessageInfo(mi)
 | 
			
		||||
		}
 | 
			
		||||
		return ms
 | 
			
		||||
	}
 | 
			
		||||
	return mi.MessageOf(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
 | 
			
		||||
func (*Config) Descriptor() ([]byte, []int) {
 | 
			
		||||
	return file_transport_internet_grpc_config_proto_rawDescGZIP(), []int{0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) GetHost() string {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.Host
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) GetServiceName() string {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.ServiceName
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) GetMultiMode() bool {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.MultiMode
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var File_transport_internet_grpc_config_proto protoreflect.FileDescriptor
 | 
			
		||||
 | 
			
		||||
var file_transport_internet_grpc_config_proto_rawDesc = []byte{
 | 
			
		||||
	0x0a, 0x24, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
 | 
			
		||||
	0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
 | 
			
		||||
	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x25, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
 | 
			
		||||
	0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
 | 
			
		||||
	0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x5e, 0x0a,
 | 
			
		||||
	0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18,
 | 
			
		||||
	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73,
 | 
			
		||||
	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d,
 | 
			
		||||
	0x0a, 0x0a, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x08, 0x52, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x6f, 0x64, 0x65, 0x42, 0x33, 0x5a,
 | 
			
		||||
	0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73,
 | 
			
		||||
	0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73,
 | 
			
		||||
	0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72,
 | 
			
		||||
	0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	file_transport_internet_grpc_config_proto_rawDescOnce sync.Once
 | 
			
		||||
	file_transport_internet_grpc_config_proto_rawDescData = file_transport_internet_grpc_config_proto_rawDesc
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func file_transport_internet_grpc_config_proto_rawDescGZIP() []byte {
 | 
			
		||||
	file_transport_internet_grpc_config_proto_rawDescOnce.Do(func() {
 | 
			
		||||
		file_transport_internet_grpc_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_grpc_config_proto_rawDescData)
 | 
			
		||||
	})
 | 
			
		||||
	return file_transport_internet_grpc_config_proto_rawDescData
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var file_transport_internet_grpc_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 | 
			
		||||
var file_transport_internet_grpc_config_proto_goTypes = []interface{}{
 | 
			
		||||
	(*Config)(nil), // 0: xray.transport.internet.grpc.encoding.Config
 | 
			
		||||
}
 | 
			
		||||
var file_transport_internet_grpc_config_proto_depIdxs = []int32{
 | 
			
		||||
	0, // [0:0] is the sub-list for method output_type
 | 
			
		||||
	0, // [0:0] is the sub-list for method input_type
 | 
			
		||||
	0, // [0:0] is the sub-list for extension type_name
 | 
			
		||||
	0, // [0:0] is the sub-list for extension extendee
 | 
			
		||||
	0, // [0:0] is the sub-list for field type_name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() { file_transport_internet_grpc_config_proto_init() }
 | 
			
		||||
func file_transport_internet_grpc_config_proto_init() {
 | 
			
		||||
	if File_transport_internet_grpc_config_proto != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if !protoimpl.UnsafeEnabled {
 | 
			
		||||
		file_transport_internet_grpc_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
 | 
			
		||||
			switch v := v.(*Config); i {
 | 
			
		||||
			case 0:
 | 
			
		||||
				return &v.state
 | 
			
		||||
			case 1:
 | 
			
		||||
				return &v.sizeCache
 | 
			
		||||
			case 2:
 | 
			
		||||
				return &v.unknownFields
 | 
			
		||||
			default:
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	type x struct{}
 | 
			
		||||
	out := protoimpl.TypeBuilder{
 | 
			
		||||
		File: protoimpl.DescBuilder{
 | 
			
		||||
			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 | 
			
		||||
			RawDescriptor: file_transport_internet_grpc_config_proto_rawDesc,
 | 
			
		||||
			NumEnums:      0,
 | 
			
		||||
			NumMessages:   1,
 | 
			
		||||
			NumExtensions: 0,
 | 
			
		||||
			NumServices:   0,
 | 
			
		||||
		},
 | 
			
		||||
		GoTypes:           file_transport_internet_grpc_config_proto_goTypes,
 | 
			
		||||
		DependencyIndexes: file_transport_internet_grpc_config_proto_depIdxs,
 | 
			
		||||
		MessageInfos:      file_transport_internet_grpc_config_proto_msgTypes,
 | 
			
		||||
	}.Build()
 | 
			
		||||
	File_transport_internet_grpc_config_proto = out.File
 | 
			
		||||
	file_transport_internet_grpc_config_proto_rawDesc = nil
 | 
			
		||||
	file_transport_internet_grpc_config_proto_goTypes = nil
 | 
			
		||||
	file_transport_internet_grpc_config_proto_depIdxs = nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								transport/internet/grpc/config.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								transport/internet/grpc/config.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package xray.transport.internet.grpc.encoding;
 | 
			
		||||
option go_package = "github.com/xtls/xray-core/transport/internet/grpc";
 | 
			
		||||
 | 
			
		||||
message Config {
 | 
			
		||||
  string host = 1;
 | 
			
		||||
  string service_name = 2;
 | 
			
		||||
  bool multi_mode = 3;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										130
									
								
								transport/internet/grpc/dial.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								transport/internet/grpc/dial.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
			
		||||
package grpc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	gonet "net"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"google.golang.org/grpc"
 | 
			
		||||
	"google.golang.org/grpc/backoff"
 | 
			
		||||
	"google.golang.org/grpc/connectivity"
 | 
			
		||||
	"google.golang.org/grpc/credentials"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net"
 | 
			
		||||
	"github.com/xtls/xray-core/common/session"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/grpc/encoding"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/tls"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
 | 
			
		||||
	newError("creating connection to ", dest).WriteToLog(session.ExportIDToError(ctx))
 | 
			
		||||
 | 
			
		||||
	conn, err := dialgRPC(ctx, dest, streamSettings)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, newError("failed to dial gRPC").Base(err)
 | 
			
		||||
	}
 | 
			
		||||
	return internet.Connection(conn), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	common.Must(internet.RegisterTransportDialer(protocolName, Dial))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type dialerConf struct {
 | 
			
		||||
	net.Destination
 | 
			
		||||
	*internet.SocketConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	globalDialerMap    map[dialerConf]*grpc.ClientConn
 | 
			
		||||
	globalDialerAccess sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func dialgRPC(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {
 | 
			
		||||
	grpcSettings := streamSettings.ProtocolSettings.(*Config)
 | 
			
		||||
 | 
			
		||||
	config := tls.ConfigFromStreamSettings(streamSettings)
 | 
			
		||||
	var dialOption = grpc.WithInsecure()
 | 
			
		||||
 | 
			
		||||
	if config != nil {
 | 
			
		||||
		dialOption = grpc.WithTransportCredentials(credentials.NewTLS(config.GetTLSConfig()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn, err := getGrpcClient(ctx, dest, dialOption, streamSettings.SocketSettings)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, newError("Cannot dial gRPC").Base(err)
 | 
			
		||||
	}
 | 
			
		||||
	client := encoding.NewGRPCServiceClient(conn)
 | 
			
		||||
	if grpcSettings.MultiMode {
 | 
			
		||||
		newError("using gRPC multi mode").AtDebug().WriteToLog()
 | 
			
		||||
		grpcService, err := client.(encoding.GRPCServiceClientX).TunMultiCustomName(ctx, grpcSettings.ServiceName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, newError("Cannot dial gRPC").Base(err)
 | 
			
		||||
		}
 | 
			
		||||
		return encoding.NewMultiHunkConn(grpcService, nil), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	grpcService, err := client.(encoding.GRPCServiceClientX).TunCustomName(ctx, grpcSettings.ServiceName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, newError("Cannot dial gRPC").Base(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return encoding.NewHunkConn(grpcService, nil), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getGrpcClient(ctx context.Context, dest net.Destination, dialOption grpc.DialOption, sockopt *internet.SocketConfig) (*grpc.ClientConn, error) {
 | 
			
		||||
	globalDialerAccess.Lock()
 | 
			
		||||
	defer globalDialerAccess.Unlock()
 | 
			
		||||
 | 
			
		||||
	if globalDialerMap == nil {
 | 
			
		||||
		globalDialerMap = make(map[dialerConf]*grpc.ClientConn)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if client, found := globalDialerMap[dialerConf{dest, sockopt}]; found && client.GetState() != connectivity.Shutdown {
 | 
			
		||||
		return client, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn, err := grpc.Dial(
 | 
			
		||||
		gonet.JoinHostPort(dest.Address.String(), dest.Port.String()),
 | 
			
		||||
		dialOption,
 | 
			
		||||
		grpc.WithConnectParams(grpc.ConnectParams{
 | 
			
		||||
			Backoff: backoff.Config{
 | 
			
		||||
				BaseDelay:  500 * time.Millisecond,
 | 
			
		||||
				Multiplier: 1.5,
 | 
			
		||||
				Jitter:     0.2,
 | 
			
		||||
				MaxDelay:   19 * time.Second,
 | 
			
		||||
			},
 | 
			
		||||
			MinConnectTimeout: 5 * time.Second,
 | 
			
		||||
		}),
 | 
			
		||||
		grpc.WithContextDialer(func(gctx context.Context, s string) (gonet.Conn, error) {
 | 
			
		||||
			gctx = session.ContextWithID(gctx, session.IDFromContext(ctx))
 | 
			
		||||
			gctx = session.ContextWithOutbound(gctx, session.OutboundFromContext(ctx))
 | 
			
		||||
 | 
			
		||||
			rawHost, rawPort, err := net.SplitHostPort(s)
 | 
			
		||||
			select {
 | 
			
		||||
			case <-gctx.Done():
 | 
			
		||||
				return nil, gctx.Err()
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if len(rawPort) == 0 {
 | 
			
		||||
				rawPort = "443"
 | 
			
		||||
			}
 | 
			
		||||
			port, err := net.PortFromString(rawPort)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			address := net.ParseAddress(rawHost)
 | 
			
		||||
			return internet.DialSystem(gctx, net.TCPDestination(address, port), sockopt)
 | 
			
		||||
		}),
 | 
			
		||||
	)
 | 
			
		||||
	globalDialerMap[dialerConf{dest, sockopt}] = conn
 | 
			
		||||
	return conn, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								transport/internet/grpc/encoding/customSeviceName.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								transport/internet/grpc/encoding/customSeviceName.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
package encoding
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"google.golang.org/grpc"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func ServerDesc(name string) grpc.ServiceDesc {
 | 
			
		||||
	return grpc.ServiceDesc{
 | 
			
		||||
		ServiceName: name,
 | 
			
		||||
		HandlerType: (*GRPCServiceServer)(nil),
 | 
			
		||||
		Methods:     []grpc.MethodDesc{},
 | 
			
		||||
		Streams: []grpc.StreamDesc{
 | 
			
		||||
			{
 | 
			
		||||
				StreamName:    "Tun",
 | 
			
		||||
				Handler:       _GRPCService_Tun_Handler,
 | 
			
		||||
				ServerStreams: true,
 | 
			
		||||
				ClientStreams: true,
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				StreamName:    "TunMulti",
 | 
			
		||||
				Handler:       _GRPCService_TunMulti_Handler,
 | 
			
		||||
				ServerStreams: true,
 | 
			
		||||
				ClientStreams: true,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Metadata: "grpc.proto",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *gRPCServiceClient) TunCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunClient, error) {
 | 
			
		||||
	stream, err := c.cc.NewStream(ctx, &ServerDesc(name).Streams[0], "/"+name+"/Tun", opts...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	x := &gRPCServiceTunClient{stream}
 | 
			
		||||
	return x, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *gRPCServiceClient) TunMultiCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) {
 | 
			
		||||
	stream, err := c.cc.NewStream(ctx, &ServerDesc(name).Streams[0], "/"+name+"/TunMulti", opts...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	x := &gRPCServiceTunMultiClient{stream}
 | 
			
		||||
	return x, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GRPCServiceClientX interface {
 | 
			
		||||
	TunCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunClient, error)
 | 
			
		||||
	TunMultiCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error)
 | 
			
		||||
	Tun(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunClient, error)
 | 
			
		||||
	TunMulti(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RegisterGRPCServiceServerX(s *grpc.Server, srv GRPCServiceServer, name string) {
 | 
			
		||||
	desc := ServerDesc(name)
 | 
			
		||||
	s.RegisterService(&desc, srv)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								transport/internet/grpc/encoding/encoding.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								transport/internet/grpc/encoding/encoding.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
package encoding
 | 
			
		||||
 | 
			
		||||
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
 | 
			
		||||
							
								
								
									
										9
									
								
								transport/internet/grpc/encoding/errors.generated.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								transport/internet/grpc/encoding/errors.generated.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
package encoding
 | 
			
		||||
 | 
			
		||||
import "github.com/xtls/xray-core/common/errors"
 | 
			
		||||
 | 
			
		||||
type errPathObjHolder struct{}
 | 
			
		||||
 | 
			
		||||
func newError(values ...interface{}) *errors.Error {
 | 
			
		||||
	return errors.New(values...).WithPathObj(errPathObjHolder{})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										123
									
								
								transport/internet/grpc/encoding/hunkconn.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								transport/internet/grpc/encoding/hunkconn.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
package encoding
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/common/buf"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net/cnc"
 | 
			
		||||
	"github.com/xtls/xray-core/common/signal/done"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type HunkConn interface {
 | 
			
		||||
	Send(*Hunk) error
 | 
			
		||||
	Recv() (*Hunk, error)
 | 
			
		||||
	SendMsg(m interface{}) error
 | 
			
		||||
	RecvMsg(m interface{}) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type StreamCloser interface {
 | 
			
		||||
	CloseSend() error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type HunkReaderWriter struct {
 | 
			
		||||
	hc     HunkConn
 | 
			
		||||
	cancel context.CancelFunc
 | 
			
		||||
	done   *done.Instance
 | 
			
		||||
 | 
			
		||||
	buf   []byte
 | 
			
		||||
	index int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHunkReadWriter(hc HunkConn, cancel context.CancelFunc) *HunkReaderWriter {
 | 
			
		||||
	return &HunkReaderWriter{hc, cancel, done.New(), nil, 0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHunkConn(hc HunkConn, cancel context.CancelFunc) net.Conn {
 | 
			
		||||
	wrc := NewHunkReadWriter(hc, cancel)
 | 
			
		||||
	return cnc.NewConnection(
 | 
			
		||||
		cnc.ConnectionInput(wrc),
 | 
			
		||||
		cnc.ConnectionOutput(wrc),
 | 
			
		||||
		cnc.ConnectionOnClose(wrc),
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *HunkReaderWriter) forceFetch() error {
 | 
			
		||||
	hunk, err := h.hc.Recv()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return newError("failed to fetch hunk from gRPC tunnel").Base(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h.buf = hunk.Data
 | 
			
		||||
	h.index = 0
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *HunkReaderWriter) Read(buf []byte) (int, error) {
 | 
			
		||||
	if h.done.Done() {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if h.index >= len(h.buf) {
 | 
			
		||||
		if err := h.forceFetch(); err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	n := copy(buf, h.buf[h.index:])
 | 
			
		||||
	h.index += n
 | 
			
		||||
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *HunkReaderWriter) ReadMultiBuffer() (buf.MultiBuffer, error) {
 | 
			
		||||
	if h.done.Done() {
 | 
			
		||||
		return nil, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	if h.index >= len(h.buf) {
 | 
			
		||||
		if err := h.forceFetch(); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cap(h.buf) == buf.Size {
 | 
			
		||||
		b := h.buf
 | 
			
		||||
		h.index = len(h.buf)
 | 
			
		||||
		return buf.MultiBuffer{buf.NewExisted(b)}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b := buf.New()
 | 
			
		||||
	_, err := b.ReadFrom(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return buf.MultiBuffer{b}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *HunkReaderWriter) Write(buf []byte) (int, error) {
 | 
			
		||||
	if h.done.Done() {
 | 
			
		||||
		return 0, io.ErrClosedPipe
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := h.hc.Send(&Hunk{Data: buf[:]})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, newError("failed to send data over gRPC tunnel").Base(err)
 | 
			
		||||
	}
 | 
			
		||||
	return len(buf), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *HunkReaderWriter) Close() error {
 | 
			
		||||
	if h.cancel != nil {
 | 
			
		||||
		h.cancel()
 | 
			
		||||
	}
 | 
			
		||||
	if sc, match := h.hc.(StreamCloser); match {
 | 
			
		||||
		return sc.CloseSend()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return h.done.Close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								transport/internet/grpc/encoding/multiconn.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								transport/internet/grpc/encoding/multiconn.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
package encoding
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/common/buf"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net/cnc"
 | 
			
		||||
	"github.com/xtls/xray-core/common/signal/done"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MultiHunkConn interface {
 | 
			
		||||
	Send(*MultiHunk) error
 | 
			
		||||
	Recv() (*MultiHunk, error)
 | 
			
		||||
	SendMsg(m interface{}) error
 | 
			
		||||
	RecvMsg(m interface{}) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MultiHunkReaderWriter struct {
 | 
			
		||||
	hc     MultiHunkConn
 | 
			
		||||
	cancel context.CancelFunc
 | 
			
		||||
	done   *done.Instance
 | 
			
		||||
 | 
			
		||||
	buf [][]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMultiHunkReadWriter(hc MultiHunkConn, cancel context.CancelFunc) *MultiHunkReaderWriter {
 | 
			
		||||
	return &MultiHunkReaderWriter{hc, cancel, done.New(), nil}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMultiHunkConn(hc MultiHunkConn, cancel context.CancelFunc) net.Conn {
 | 
			
		||||
	wrc := NewMultiHunkReadWriter(hc, cancel)
 | 
			
		||||
	return cnc.NewConnection(
 | 
			
		||||
		cnc.ConnectionInputMulti(wrc),
 | 
			
		||||
		cnc.ConnectionOutputMulti(wrc),
 | 
			
		||||
		cnc.ConnectionOnClose(wrc),
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *MultiHunkReaderWriter) forceFetch() error {
 | 
			
		||||
	hunk, err := h.hc.Recv()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return newError("failed to fetch hunk from gRPC tunnel").Base(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h.buf = hunk.Data
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *MultiHunkReaderWriter) ReadMultiBuffer() (buf.MultiBuffer, error) {
 | 
			
		||||
	if h.done.Done() {
 | 
			
		||||
		return nil, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := h.forceFetch(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var mb = make(buf.MultiBuffer, 0, len(h.buf))
 | 
			
		||||
	for _, b := range h.buf {
 | 
			
		||||
		if cap(b) >= buf.Size {
 | 
			
		||||
			mb = append(mb, buf.NewExisted(b))
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		nb := buf.New()
 | 
			
		||||
		nb.Extend(int32(len(b)))
 | 
			
		||||
		copy(nb.Bytes(), b)
 | 
			
		||||
 | 
			
		||||
		mb = append(mb, nb)
 | 
			
		||||
	}
 | 
			
		||||
	return mb, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *MultiHunkReaderWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
 | 
			
		||||
	defer buf.ReleaseMulti(mb)
 | 
			
		||||
	if h.done.Done() {
 | 
			
		||||
		return io.ErrClosedPipe
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hunk := &MultiHunk{Data: make([][]byte, len(mb))}
 | 
			
		||||
	for _, b := range mb {
 | 
			
		||||
		hunk.Data = append(hunk.Data, b.Bytes())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := h.hc.Send(hunk)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *MultiHunkReaderWriter) Close() error {
 | 
			
		||||
	if h.cancel != nil {
 | 
			
		||||
		h.cancel()
 | 
			
		||||
	}
 | 
			
		||||
	if sc, match := h.hc.(StreamCloser); match {
 | 
			
		||||
		return sc.CloseSend()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return h.done.Close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										234
									
								
								transport/internet/grpc/encoding/stream.pb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								transport/internet/grpc/encoding/stream.pb.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,234 @@
 | 
			
		||||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
			
		||||
// versions:
 | 
			
		||||
// 	protoc-gen-go v1.25.0
 | 
			
		||||
// 	protoc        v3.15.6
 | 
			
		||||
// source: transport/internet/grpc/encoding/stream.proto
 | 
			
		||||
 | 
			
		||||
package encoding
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	proto "github.com/golang/protobuf/proto"
 | 
			
		||||
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 | 
			
		||||
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 | 
			
		||||
	reflect "reflect"
 | 
			
		||||
	sync "sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Verify that this generated code is sufficiently up-to-date.
 | 
			
		||||
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
 | 
			
		||||
	// Verify that runtime/protoimpl is sufficiently up-to-date.
 | 
			
		||||
	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This is a compile-time assertion that a sufficiently up-to-date version
 | 
			
		||||
// of the legacy proto package is being used.
 | 
			
		||||
const _ = proto.ProtoPackageIsVersion4
 | 
			
		||||
 | 
			
		||||
type Hunk struct {
 | 
			
		||||
	state         protoimpl.MessageState
 | 
			
		||||
	sizeCache     protoimpl.SizeCache
 | 
			
		||||
	unknownFields protoimpl.UnknownFields
 | 
			
		||||
 | 
			
		||||
	Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Hunk) Reset() {
 | 
			
		||||
	*x = Hunk{}
 | 
			
		||||
	if protoimpl.UnsafeEnabled {
 | 
			
		||||
		mi := &file_transport_internet_grpc_encoding_stream_proto_msgTypes[0]
 | 
			
		||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
			
		||||
		ms.StoreMessageInfo(mi)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Hunk) String() string {
 | 
			
		||||
	return protoimpl.X.MessageStringOf(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*Hunk) ProtoMessage() {}
 | 
			
		||||
 | 
			
		||||
func (x *Hunk) ProtoReflect() protoreflect.Message {
 | 
			
		||||
	mi := &file_transport_internet_grpc_encoding_stream_proto_msgTypes[0]
 | 
			
		||||
	if protoimpl.UnsafeEnabled && x != nil {
 | 
			
		||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
			
		||||
		if ms.LoadMessageInfo() == nil {
 | 
			
		||||
			ms.StoreMessageInfo(mi)
 | 
			
		||||
		}
 | 
			
		||||
		return ms
 | 
			
		||||
	}
 | 
			
		||||
	return mi.MessageOf(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Deprecated: Use Hunk.ProtoReflect.Descriptor instead.
 | 
			
		||||
func (*Hunk) Descriptor() ([]byte, []int) {
 | 
			
		||||
	return file_transport_internet_grpc_encoding_stream_proto_rawDescGZIP(), []int{0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Hunk) GetData() []byte {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.Data
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MultiHunk struct {
 | 
			
		||||
	state         protoimpl.MessageState
 | 
			
		||||
	sizeCache     protoimpl.SizeCache
 | 
			
		||||
	unknownFields protoimpl.UnknownFields
 | 
			
		||||
 | 
			
		||||
	Data [][]byte `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *MultiHunk) Reset() {
 | 
			
		||||
	*x = MultiHunk{}
 | 
			
		||||
	if protoimpl.UnsafeEnabled {
 | 
			
		||||
		mi := &file_transport_internet_grpc_encoding_stream_proto_msgTypes[1]
 | 
			
		||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
			
		||||
		ms.StoreMessageInfo(mi)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *MultiHunk) String() string {
 | 
			
		||||
	return protoimpl.X.MessageStringOf(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*MultiHunk) ProtoMessage() {}
 | 
			
		||||
 | 
			
		||||
func (x *MultiHunk) ProtoReflect() protoreflect.Message {
 | 
			
		||||
	mi := &file_transport_internet_grpc_encoding_stream_proto_msgTypes[1]
 | 
			
		||||
	if protoimpl.UnsafeEnabled && x != nil {
 | 
			
		||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
			
		||||
		if ms.LoadMessageInfo() == nil {
 | 
			
		||||
			ms.StoreMessageInfo(mi)
 | 
			
		||||
		}
 | 
			
		||||
		return ms
 | 
			
		||||
	}
 | 
			
		||||
	return mi.MessageOf(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Deprecated: Use MultiHunk.ProtoReflect.Descriptor instead.
 | 
			
		||||
func (*MultiHunk) Descriptor() ([]byte, []int) {
 | 
			
		||||
	return file_transport_internet_grpc_encoding_stream_proto_rawDescGZIP(), []int{1}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *MultiHunk) GetData() [][]byte {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.Data
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var File_transport_internet_grpc_encoding_stream_proto protoreflect.FileDescriptor
 | 
			
		||||
 | 
			
		||||
var file_transport_internet_grpc_encoding_stream_proto_rawDesc = []byte{
 | 
			
		||||
	0x0a, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
 | 
			
		||||
	0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69,
 | 
			
		||||
	0x6e, 0x67, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
 | 
			
		||||
	0x25, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
 | 
			
		||||
	0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e,
 | 
			
		||||
	0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x1a, 0x0a, 0x04, 0x48, 0x75, 0x6e, 0x6b, 0x12, 0x12,
 | 
			
		||||
	0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61,
 | 
			
		||||
	0x74, 0x61, 0x22, 0x1f, 0x0a, 0x09, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x48, 0x75, 0x6e, 0x6b, 0x12,
 | 
			
		||||
	0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x64,
 | 
			
		||||
	0x61, 0x74, 0x61, 0x32, 0xe6, 0x01, 0x0a, 0x0b, 0x47, 0x52, 0x50, 0x43, 0x53, 0x65, 0x72, 0x76,
 | 
			
		||||
	0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x03, 0x54, 0x75, 0x6e, 0x12, 0x2b, 0x2e, 0x78, 0x72, 0x61,
 | 
			
		||||
	0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
 | 
			
		||||
	0x72, 0x6e, 0x65, 0x74, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69,
 | 
			
		||||
	0x6e, 0x67, 0x2e, 0x48, 0x75, 0x6e, 0x6b, 0x1a, 0x2b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74,
 | 
			
		||||
	0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
 | 
			
		||||
	0x74, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e,
 | 
			
		||||
	0x48, 0x75, 0x6e, 0x6b, 0x28, 0x01, 0x30, 0x01, 0x12, 0x72, 0x0a, 0x08, 0x54, 0x75, 0x6e, 0x4d,
 | 
			
		||||
	0x75, 0x6c, 0x74, 0x69, 0x12, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
 | 
			
		||||
	0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x67,
 | 
			
		||||
	0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x75, 0x6c,
 | 
			
		||||
	0x74, 0x69, 0x48, 0x75, 0x6e, 0x6b, 0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72,
 | 
			
		||||
	0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
 | 
			
		||||
	0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4d,
 | 
			
		||||
	0x75, 0x6c, 0x74, 0x69, 0x48, 0x75, 0x6e, 0x6b, 0x28, 0x01, 0x30, 0x01, 0x42, 0x3c, 0x5a, 0x3a,
 | 
			
		||||
	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
 | 
			
		||||
	0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
 | 
			
		||||
	0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70,
 | 
			
		||||
	0x63, 0x2f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
 | 
			
		||||
	0x6f, 0x33,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	file_transport_internet_grpc_encoding_stream_proto_rawDescOnce sync.Once
 | 
			
		||||
	file_transport_internet_grpc_encoding_stream_proto_rawDescData = file_transport_internet_grpc_encoding_stream_proto_rawDesc
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func file_transport_internet_grpc_encoding_stream_proto_rawDescGZIP() []byte {
 | 
			
		||||
	file_transport_internet_grpc_encoding_stream_proto_rawDescOnce.Do(func() {
 | 
			
		||||
		file_transport_internet_grpc_encoding_stream_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_grpc_encoding_stream_proto_rawDescData)
 | 
			
		||||
	})
 | 
			
		||||
	return file_transport_internet_grpc_encoding_stream_proto_rawDescData
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var file_transport_internet_grpc_encoding_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
 | 
			
		||||
var file_transport_internet_grpc_encoding_stream_proto_goTypes = []interface{}{
 | 
			
		||||
	(*Hunk)(nil),      // 0: xray.transport.internet.grpc.encoding.Hunk
 | 
			
		||||
	(*MultiHunk)(nil), // 1: xray.transport.internet.grpc.encoding.MultiHunk
 | 
			
		||||
}
 | 
			
		||||
var file_transport_internet_grpc_encoding_stream_proto_depIdxs = []int32{
 | 
			
		||||
	0, // 0: xray.transport.internet.grpc.encoding.GRPCService.Tun:input_type -> xray.transport.internet.grpc.encoding.Hunk
 | 
			
		||||
	1, // 1: xray.transport.internet.grpc.encoding.GRPCService.TunMulti:input_type -> xray.transport.internet.grpc.encoding.MultiHunk
 | 
			
		||||
	0, // 2: xray.transport.internet.grpc.encoding.GRPCService.Tun:output_type -> xray.transport.internet.grpc.encoding.Hunk
 | 
			
		||||
	1, // 3: xray.transport.internet.grpc.encoding.GRPCService.TunMulti:output_type -> xray.transport.internet.grpc.encoding.MultiHunk
 | 
			
		||||
	2, // [2:4] is the sub-list for method output_type
 | 
			
		||||
	0, // [0:2] is the sub-list for method input_type
 | 
			
		||||
	0, // [0:0] is the sub-list for extension type_name
 | 
			
		||||
	0, // [0:0] is the sub-list for extension extendee
 | 
			
		||||
	0, // [0:0] is the sub-list for field type_name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() { file_transport_internet_grpc_encoding_stream_proto_init() }
 | 
			
		||||
func file_transport_internet_grpc_encoding_stream_proto_init() {
 | 
			
		||||
	if File_transport_internet_grpc_encoding_stream_proto != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if !protoimpl.UnsafeEnabled {
 | 
			
		||||
		file_transport_internet_grpc_encoding_stream_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
 | 
			
		||||
			switch v := v.(*Hunk); i {
 | 
			
		||||
			case 0:
 | 
			
		||||
				return &v.state
 | 
			
		||||
			case 1:
 | 
			
		||||
				return &v.sizeCache
 | 
			
		||||
			case 2:
 | 
			
		||||
				return &v.unknownFields
 | 
			
		||||
			default:
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		file_transport_internet_grpc_encoding_stream_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
 | 
			
		||||
			switch v := v.(*MultiHunk); i {
 | 
			
		||||
			case 0:
 | 
			
		||||
				return &v.state
 | 
			
		||||
			case 1:
 | 
			
		||||
				return &v.sizeCache
 | 
			
		||||
			case 2:
 | 
			
		||||
				return &v.unknownFields
 | 
			
		||||
			default:
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	type x struct{}
 | 
			
		||||
	out := protoimpl.TypeBuilder{
 | 
			
		||||
		File: protoimpl.DescBuilder{
 | 
			
		||||
			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 | 
			
		||||
			RawDescriptor: file_transport_internet_grpc_encoding_stream_proto_rawDesc,
 | 
			
		||||
			NumEnums:      0,
 | 
			
		||||
			NumMessages:   2,
 | 
			
		||||
			NumExtensions: 0,
 | 
			
		||||
			NumServices:   1,
 | 
			
		||||
		},
 | 
			
		||||
		GoTypes:           file_transport_internet_grpc_encoding_stream_proto_goTypes,
 | 
			
		||||
		DependencyIndexes: file_transport_internet_grpc_encoding_stream_proto_depIdxs,
 | 
			
		||||
		MessageInfos:      file_transport_internet_grpc_encoding_stream_proto_msgTypes,
 | 
			
		||||
	}.Build()
 | 
			
		||||
	File_transport_internet_grpc_encoding_stream_proto = out.File
 | 
			
		||||
	file_transport_internet_grpc_encoding_stream_proto_rawDesc = nil
 | 
			
		||||
	file_transport_internet_grpc_encoding_stream_proto_goTypes = nil
 | 
			
		||||
	file_transport_internet_grpc_encoding_stream_proto_depIdxs = nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								transport/internet/grpc/encoding/stream.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								transport/internet/grpc/encoding/stream.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package xray.transport.internet.grpc.encoding;
 | 
			
		||||
option go_package = "github.com/xtls/xray-core/transport/internet/grpc/encoding";
 | 
			
		||||
 | 
			
		||||
message Hunk {
 | 
			
		||||
  bytes data = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message MultiHunk {
 | 
			
		||||
   repeated bytes data = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
service GRPCService {
 | 
			
		||||
  rpc Tun (stream Hunk) returns (stream Hunk);
 | 
			
		||||
  rpc TunMulti (stream MultiHunk) returns (stream MultiHunk);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										201
									
								
								transport/internet/grpc/encoding/stream_grpc.pb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								transport/internet/grpc/encoding/stream_grpc.pb.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
			
		||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package encoding
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	context "context"
 | 
			
		||||
	grpc "google.golang.org/grpc"
 | 
			
		||||
	codes "google.golang.org/grpc/codes"
 | 
			
		||||
	status "google.golang.org/grpc/status"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This is a compile-time assertion to ensure that this generated file
 | 
			
		||||
// is compatible with the grpc package it is being compiled against.
 | 
			
		||||
// Requires gRPC-Go v1.32.0 or later.
 | 
			
		||||
const _ = grpc.SupportPackageIsVersion7
 | 
			
		||||
 | 
			
		||||
// GRPCServiceClient is the client API for GRPCService service.
 | 
			
		||||
//
 | 
			
		||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
 | 
			
		||||
type GRPCServiceClient interface {
 | 
			
		||||
	Tun(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunClient, error)
 | 
			
		||||
	TunMulti(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type gRPCServiceClient struct {
 | 
			
		||||
	cc grpc.ClientConnInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewGRPCServiceClient(cc grpc.ClientConnInterface) GRPCServiceClient {
 | 
			
		||||
	return &gRPCServiceClient{cc}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *gRPCServiceClient) Tun(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunClient, error) {
 | 
			
		||||
	stream, err := c.cc.NewStream(ctx, &GRPCService_ServiceDesc.Streams[0], "/xray.transport.internet.grpc.encoding.GRPCService/Tun", opts...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	x := &gRPCServiceTunClient{stream}
 | 
			
		||||
	return x, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GRPCService_TunClient interface {
 | 
			
		||||
	Send(*Hunk) error
 | 
			
		||||
	Recv() (*Hunk, error)
 | 
			
		||||
	grpc.ClientStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type gRPCServiceTunClient struct {
 | 
			
		||||
	grpc.ClientStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *gRPCServiceTunClient) Send(m *Hunk) error {
 | 
			
		||||
	return x.ClientStream.SendMsg(m)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *gRPCServiceTunClient) Recv() (*Hunk, error) {
 | 
			
		||||
	m := new(Hunk)
 | 
			
		||||
	if err := x.ClientStream.RecvMsg(m); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return m, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *gRPCServiceClient) TunMulti(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) {
 | 
			
		||||
	stream, err := c.cc.NewStream(ctx, &GRPCService_ServiceDesc.Streams[1], "/xray.transport.internet.grpc.encoding.GRPCService/TunMulti", opts...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	x := &gRPCServiceTunMultiClient{stream}
 | 
			
		||||
	return x, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GRPCService_TunMultiClient interface {
 | 
			
		||||
	Send(*MultiHunk) error
 | 
			
		||||
	Recv() (*MultiHunk, error)
 | 
			
		||||
	grpc.ClientStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type gRPCServiceTunMultiClient struct {
 | 
			
		||||
	grpc.ClientStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *gRPCServiceTunMultiClient) Send(m *MultiHunk) error {
 | 
			
		||||
	return x.ClientStream.SendMsg(m)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *gRPCServiceTunMultiClient) Recv() (*MultiHunk, error) {
 | 
			
		||||
	m := new(MultiHunk)
 | 
			
		||||
	if err := x.ClientStream.RecvMsg(m); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return m, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GRPCServiceServer is the server API for GRPCService service.
 | 
			
		||||
// All implementations must embed UnimplementedGRPCServiceServer
 | 
			
		||||
// for forward compatibility
 | 
			
		||||
type GRPCServiceServer interface {
 | 
			
		||||
	Tun(GRPCService_TunServer) error
 | 
			
		||||
	TunMulti(GRPCService_TunMultiServer) error
 | 
			
		||||
	mustEmbedUnimplementedGRPCServiceServer()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnimplementedGRPCServiceServer must be embedded to have forward compatible implementations.
 | 
			
		||||
type UnimplementedGRPCServiceServer struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (UnimplementedGRPCServiceServer) Tun(GRPCService_TunServer) error {
 | 
			
		||||
	return status.Errorf(codes.Unimplemented, "method Tun not implemented")
 | 
			
		||||
}
 | 
			
		||||
func (UnimplementedGRPCServiceServer) TunMulti(GRPCService_TunMultiServer) error {
 | 
			
		||||
	return status.Errorf(codes.Unimplemented, "method TunMulti not implemented")
 | 
			
		||||
}
 | 
			
		||||
func (UnimplementedGRPCServiceServer) mustEmbedUnimplementedGRPCServiceServer() {}
 | 
			
		||||
 | 
			
		||||
// UnsafeGRPCServiceServer may be embedded to opt out of forward compatibility for this service.
 | 
			
		||||
// Use of this interface is not recommended, as added methods to GRPCServiceServer will
 | 
			
		||||
// result in compilation errors.
 | 
			
		||||
type UnsafeGRPCServiceServer interface {
 | 
			
		||||
	mustEmbedUnimplementedGRPCServiceServer()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RegisterGRPCServiceServer(s grpc.ServiceRegistrar, srv GRPCServiceServer) {
 | 
			
		||||
	s.RegisterService(&GRPCService_ServiceDesc, srv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _GRPCService_Tun_Handler(srv interface{}, stream grpc.ServerStream) error {
 | 
			
		||||
	return srv.(GRPCServiceServer).Tun(&gRPCServiceTunServer{stream})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GRPCService_TunServer interface {
 | 
			
		||||
	Send(*Hunk) error
 | 
			
		||||
	Recv() (*Hunk, error)
 | 
			
		||||
	grpc.ServerStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type gRPCServiceTunServer struct {
 | 
			
		||||
	grpc.ServerStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *gRPCServiceTunServer) Send(m *Hunk) error {
 | 
			
		||||
	return x.ServerStream.SendMsg(m)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *gRPCServiceTunServer) Recv() (*Hunk, error) {
 | 
			
		||||
	m := new(Hunk)
 | 
			
		||||
	if err := x.ServerStream.RecvMsg(m); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return m, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _GRPCService_TunMulti_Handler(srv interface{}, stream grpc.ServerStream) error {
 | 
			
		||||
	return srv.(GRPCServiceServer).TunMulti(&gRPCServiceTunMultiServer{stream})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GRPCService_TunMultiServer interface {
 | 
			
		||||
	Send(*MultiHunk) error
 | 
			
		||||
	Recv() (*MultiHunk, error)
 | 
			
		||||
	grpc.ServerStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type gRPCServiceTunMultiServer struct {
 | 
			
		||||
	grpc.ServerStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *gRPCServiceTunMultiServer) Send(m *MultiHunk) error {
 | 
			
		||||
	return x.ServerStream.SendMsg(m)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *gRPCServiceTunMultiServer) Recv() (*MultiHunk, error) {
 | 
			
		||||
	m := new(MultiHunk)
 | 
			
		||||
	if err := x.ServerStream.RecvMsg(m); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return m, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GRPCService_ServiceDesc is the grpc.ServiceDesc for GRPCService service.
 | 
			
		||||
// It's only intended for direct use with grpc.RegisterService,
 | 
			
		||||
// and not to be introspected or modified (even as a copy)
 | 
			
		||||
var GRPCService_ServiceDesc = grpc.ServiceDesc{
 | 
			
		||||
	ServiceName: "xray.transport.internet.grpc.encoding.GRPCService",
 | 
			
		||||
	HandlerType: (*GRPCServiceServer)(nil),
 | 
			
		||||
	Methods:     []grpc.MethodDesc{},
 | 
			
		||||
	Streams: []grpc.StreamDesc{
 | 
			
		||||
		{
 | 
			
		||||
			StreamName:    "Tun",
 | 
			
		||||
			Handler:       _GRPCService_Tun_Handler,
 | 
			
		||||
			ServerStreams: true,
 | 
			
		||||
			ClientStreams: true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			StreamName:    "TunMulti",
 | 
			
		||||
			Handler:       _GRPCService_TunMulti_Handler,
 | 
			
		||||
			ServerStreams: true,
 | 
			
		||||
			ClientStreams: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	Metadata: "transport/internet/grpc/encoding/stream.proto",
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								transport/internet/grpc/errors.generated.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								transport/internet/grpc/errors.generated.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
package grpc
 | 
			
		||||
 | 
			
		||||
import "github.com/xtls/xray-core/common/errors"
 | 
			
		||||
 | 
			
		||||
type errPathObjHolder struct{}
 | 
			
		||||
 | 
			
		||||
func newError(values ...interface{}) *errors.Error {
 | 
			
		||||
	return errors.New(values...).WithPathObj(errPathObjHolder{})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								transport/internet/grpc/grpc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								transport/internet/grpc/grpc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
package grpc
 | 
			
		||||
 | 
			
		||||
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
 | 
			
		||||
							
								
								
									
										129
									
								
								transport/internet/grpc/hub.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								transport/internet/grpc/hub.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
package grpc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"google.golang.org/grpc"
 | 
			
		||||
	"google.golang.org/grpc/credentials"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net"
 | 
			
		||||
	"github.com/xtls/xray-core/common/session"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/grpc/encoding"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/tls"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Listener struct {
 | 
			
		||||
	encoding.UnimplementedGRPCServiceServer
 | 
			
		||||
	ctx     context.Context
 | 
			
		||||
	handler internet.ConnHandler
 | 
			
		||||
	local   net.Addr
 | 
			
		||||
	config  *Config
 | 
			
		||||
	locker  *internet.FileLocker // for unix domain socket
 | 
			
		||||
 | 
			
		||||
	s *grpc.Server
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l Listener) Tun(server encoding.GRPCService_TunServer) error {
 | 
			
		||||
	tunCtx, cancel := context.WithCancel(l.ctx)
 | 
			
		||||
	l.handler(encoding.NewHunkConn(server, cancel))
 | 
			
		||||
	<-tunCtx.Done()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l Listener) TunMulti(server encoding.GRPCService_TunMultiServer) error {
 | 
			
		||||
	tunCtx, cancel := context.WithCancel(l.ctx)
 | 
			
		||||
	l.handler(encoding.NewMultiHunkConn(server, cancel))
 | 
			
		||||
	<-tunCtx.Done()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l Listener) Close() error {
 | 
			
		||||
	l.s.Stop()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l Listener) Addr() net.Addr {
 | 
			
		||||
	return l.local
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Listen(ctx context.Context, address net.Address, port net.Port, settings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {
 | 
			
		||||
	grpcSettings := settings.ProtocolSettings.(*Config)
 | 
			
		||||
	var listener *Listener
 | 
			
		||||
	if port == net.Port(0) { // unix
 | 
			
		||||
		listener = &Listener{
 | 
			
		||||
			handler: handler,
 | 
			
		||||
			local: &net.UnixAddr{
 | 
			
		||||
				Name: address.Domain(),
 | 
			
		||||
				Net:  "unix",
 | 
			
		||||
			},
 | 
			
		||||
			config: grpcSettings,
 | 
			
		||||
		}
 | 
			
		||||
	} else { // tcp
 | 
			
		||||
		listener = &Listener{
 | 
			
		||||
			handler: handler,
 | 
			
		||||
			local: &net.TCPAddr{
 | 
			
		||||
				IP:   address.IP(),
 | 
			
		||||
				Port: int(port),
 | 
			
		||||
			},
 | 
			
		||||
			config: grpcSettings,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	listener.ctx = ctx
 | 
			
		||||
 | 
			
		||||
	config := tls.ConfigFromStreamSettings(settings)
 | 
			
		||||
 | 
			
		||||
	var s *grpc.Server
 | 
			
		||||
	if config == nil {
 | 
			
		||||
		s = grpc.NewServer()
 | 
			
		||||
	} else {
 | 
			
		||||
		s = grpc.NewServer(grpc.Creds(credentials.NewTLS(config.GetTLSConfig(tls.WithNextProto("h2")))))
 | 
			
		||||
	}
 | 
			
		||||
	listener.s = s
 | 
			
		||||
 | 
			
		||||
	if settings.SocketSettings != nil && settings.SocketSettings.AcceptProxyProtocol {
 | 
			
		||||
		newError("accepting PROXY protocol").AtWarning().WriteToLog(session.ExportIDToError(ctx))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		var streamListener net.Listener
 | 
			
		||||
		var err error
 | 
			
		||||
		if port == net.Port(0) { // unix
 | 
			
		||||
			streamListener, err = internet.ListenSystem(ctx, &net.UnixAddr{
 | 
			
		||||
				Name: address.Domain(),
 | 
			
		||||
				Net:  "unix",
 | 
			
		||||
			}, settings.SocketSettings)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				newError("failed to listen on ", address).Base(err).AtError().WriteToLog(session.ExportIDToError(ctx))
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			locker := ctx.Value(address.Domain())
 | 
			
		||||
			if locker != nil {
 | 
			
		||||
				listener.locker = locker.(*internet.FileLocker)
 | 
			
		||||
			}
 | 
			
		||||
		} else { // tcp
 | 
			
		||||
			streamListener, err = internet.ListenSystem(ctx, &net.TCPAddr{
 | 
			
		||||
				IP:   address.IP(),
 | 
			
		||||
				Port: int(port),
 | 
			
		||||
			}, settings.SocketSettings)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				newError("failed to listen on ", address, ":", port).Base(err).AtError().WriteToLog(session.ExportIDToError(ctx))
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		encoding.RegisterGRPCServiceServerX(s, listener, grpcSettings.ServiceName)
 | 
			
		||||
 | 
			
		||||
		if err = s.Serve(streamListener); err != nil {
 | 
			
		||||
			newError("Listener for gRPC ended").Base(err).WriteToLog()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return listener, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	common.Must(internet.RegisterTransportListener(protocolName, Listen))
 | 
			
		||||
}
 | 
			
		||||
@@ -18,8 +18,13 @@ import (
 | 
			
		||||
	"golang.org/x/net/http2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type dialerConf struct {
 | 
			
		||||
	net.Destination
 | 
			
		||||
	*internet.SocketConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	globalDialerMap    map[net.Destination]*http.Client
 | 
			
		||||
	globalDialerMap    map[dialerConf]*http.Client
 | 
			
		||||
	globalDialerAccess sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -28,10 +33,10 @@ func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.C
 | 
			
		||||
	defer globalDialerAccess.Unlock()
 | 
			
		||||
 | 
			
		||||
	if globalDialerMap == nil {
 | 
			
		||||
		globalDialerMap = make(map[net.Destination]*http.Client)
 | 
			
		||||
		globalDialerMap = make(map[dialerConf]*http.Client)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if client, found := globalDialerMap[dest]; found {
 | 
			
		||||
	if client, found := globalDialerMap[dialerConf{dest, sockopt}]; found {
 | 
			
		||||
		return client, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -87,7 +92,7 @@ func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.C
 | 
			
		||||
		Transport: transport,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	globalDialerMap[dest] = client
 | 
			
		||||
	globalDialerMap[dialerConf{dest, sockopt}] = client
 | 
			
		||||
	return client, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user