2021-03-14 18:02:07 +03:00
|
|
|
package grpc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-07-05 16:25:03 +03:00
|
|
|
"time"
|
2021-03-14 18:02:07 +03:00
|
|
|
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/credentials"
|
2021-07-05 16:25:03 +03:00
|
|
|
"google.golang.org/grpc/keepalive"
|
2021-03-14 18:02:07 +03:00
|
|
|
|
|
|
|
"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)
|
|
|
|
|
2021-07-05 16:25:03 +03:00
|
|
|
var options []grpc.ServerOption
|
2021-03-14 18:02:07 +03:00
|
|
|
var s *grpc.Server
|
2021-07-05 16:25:03 +03:00
|
|
|
if config != nil {
|
|
|
|
options = append(options, grpc.Creds(credentials.NewTLS(config.GetTLSConfig(tls.WithNextProto("h2")))))
|
2021-03-14 18:02:07 +03:00
|
|
|
}
|
2021-07-05 16:25:03 +03:00
|
|
|
if grpcSettings.IdleTimeout > 0 || grpcSettings.HealthCheckTimeout > 0 {
|
|
|
|
options = append(options, grpc.KeepaliveParams(keepalive.ServerParameters{
|
|
|
|
Time: time.Second * time.Duration(grpcSettings.IdleTimeout),
|
|
|
|
Timeout: time.Second * time.Duration(grpcSettings.HealthCheckTimeout),
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
s = grpc.NewServer(options...)
|
2021-03-14 18:02:07 +03:00
|
|
|
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))
|
|
|
|
}
|