github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/transport/internet/grpc/hub.go (about)

     1  package grpc
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	goreality "github.com/xtls/reality"
     8  	"github.com/xtls/xray-core/common"
     9  	"github.com/xtls/xray-core/common/net"
    10  	"github.com/xtls/xray-core/common/session"
    11  	"github.com/xtls/xray-core/transport/internet"
    12  	"github.com/xtls/xray-core/transport/internet/grpc/encoding"
    13  	"github.com/xtls/xray-core/transport/internet/reality"
    14  	"github.com/xtls/xray-core/transport/internet/tls"
    15  	"google.golang.org/grpc"
    16  	"google.golang.org/grpc/credentials"
    17  	"google.golang.org/grpc/keepalive"
    18  )
    19  
    20  type Listener struct {
    21  	encoding.UnimplementedGRPCServiceServer
    22  	ctx     context.Context
    23  	handler internet.ConnHandler
    24  	local   net.Addr
    25  	config  *Config
    26  
    27  	s *grpc.Server
    28  }
    29  
    30  func (l Listener) Tun(server encoding.GRPCService_TunServer) error {
    31  	tunCtx, cancel := context.WithCancel(l.ctx)
    32  	l.handler(encoding.NewHunkConn(server, cancel))
    33  	<-tunCtx.Done()
    34  	return nil
    35  }
    36  
    37  func (l Listener) TunMulti(server encoding.GRPCService_TunMultiServer) error {
    38  	tunCtx, cancel := context.WithCancel(l.ctx)
    39  	l.handler(encoding.NewMultiHunkConn(server, cancel))
    40  	<-tunCtx.Done()
    41  	return nil
    42  }
    43  
    44  func (l Listener) Close() error {
    45  	l.s.Stop()
    46  	return nil
    47  }
    48  
    49  func (l Listener) Addr() net.Addr {
    50  	return l.local
    51  }
    52  
    53  func Listen(ctx context.Context, address net.Address, port net.Port, settings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {
    54  	grpcSettings := settings.ProtocolSettings.(*Config)
    55  	var listener *Listener
    56  	if port == net.Port(0) { // unix
    57  		listener = &Listener{
    58  			handler: handler,
    59  			local: &net.UnixAddr{
    60  				Name: address.Domain(),
    61  				Net:  "unix",
    62  			},
    63  			config: grpcSettings,
    64  		}
    65  	} else { // tcp
    66  		listener = &Listener{
    67  			handler: handler,
    68  			local: &net.TCPAddr{
    69  				IP:   address.IP(),
    70  				Port: int(port),
    71  			},
    72  			config: grpcSettings,
    73  		}
    74  	}
    75  
    76  	listener.ctx = ctx
    77  
    78  	config := tls.ConfigFromStreamSettings(settings)
    79  
    80  	var options []grpc.ServerOption
    81  	var s *grpc.Server
    82  	if config != nil {
    83  		// gRPC server may silently ignore TLS errors
    84  		options = append(options, grpc.Creds(credentials.NewTLS(config.GetTLSConfig(tls.WithNextProto("h2")))))
    85  	}
    86  	if grpcSettings.IdleTimeout > 0 || grpcSettings.HealthCheckTimeout > 0 {
    87  		options = append(options, grpc.KeepaliveParams(keepalive.ServerParameters{
    88  			Time:    time.Second * time.Duration(grpcSettings.IdleTimeout),
    89  			Timeout: time.Second * time.Duration(grpcSettings.HealthCheckTimeout),
    90  		}))
    91  	}
    92  
    93  	s = grpc.NewServer(options...)
    94  	listener.s = s
    95  
    96  	if settings.SocketSettings != nil && settings.SocketSettings.AcceptProxyProtocol {
    97  		newError("accepting PROXY protocol").AtWarning().WriteToLog(session.ExportIDToError(ctx))
    98  	}
    99  
   100  	go func() {
   101  		var streamListener net.Listener
   102  		var err error
   103  		if port == net.Port(0) { // unix
   104  			streamListener, err = internet.ListenSystem(ctx, &net.UnixAddr{
   105  				Name: address.Domain(),
   106  				Net:  "unix",
   107  			}, settings.SocketSettings)
   108  			if err != nil {
   109  				newError("failed to listen on ", address).Base(err).AtError().WriteToLog(session.ExportIDToError(ctx))
   110  				return
   111  			}
   112  		} else { // tcp
   113  			streamListener, err = internet.ListenSystem(ctx, &net.TCPAddr{
   114  				IP:   address.IP(),
   115  				Port: int(port),
   116  			}, settings.SocketSettings)
   117  			if err != nil {
   118  				newError("failed to listen on ", address, ":", port).Base(err).AtError().WriteToLog(session.ExportIDToError(ctx))
   119  				return
   120  			}
   121  		}
   122  
   123  		newError("gRPC listen for service name `" + grpcSettings.getServiceName() + "` tun `" + grpcSettings.getTunStreamName() + "` multi tun `" + grpcSettings.getTunMultiStreamName() + "`").AtDebug().WriteToLog()
   124  		encoding.RegisterGRPCServiceServerX(s, listener, grpcSettings.getServiceName(), grpcSettings.getTunStreamName(), grpcSettings.getTunMultiStreamName())
   125  
   126  		if config := reality.ConfigFromStreamSettings(settings); config != nil {
   127  			streamListener = goreality.NewListener(streamListener, config.GetREALITYConfig())
   128  		}
   129  		if err = s.Serve(streamListener); err != nil {
   130  			newError("Listener for gRPC ended").Base(err).WriteToLog()
   131  		}
   132  	}()
   133  
   134  	return listener, nil
   135  }
   136  
   137  func init() {
   138  	common.Must(internet.RegisterTransportListener(protocolName, Listen))
   139  }