2021-03-14 15:02:07 +00:00
package grpc
import (
"context"
2021-07-05 13:25:03 +00:00
"time"
2021-03-14 15:02:07 +00:00
2023-02-27 19:52:01 +00:00
goreality "github.com/xtls/reality"
2021-03-14 15:02:07 +00: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"
2023-02-27 19:52:01 +00:00
"github.com/xtls/xray-core/transport/internet/reality"
2021-03-14 15:02:07 +00:00
"github.com/xtls/xray-core/transport/internet/tls"
2022-05-18 07:29:01 +00:00
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/keepalive"
2021-03-14 15:02:07 +00:00
)
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 13:25:03 +00:00
var options [ ] grpc . ServerOption
2021-03-14 15:02:07 +00:00
var s * grpc . Server
2021-07-05 13:25:03 +00:00
if config != nil {
2021-10-22 04:01:51 +00:00
// gRPC server may silently ignore TLS errors
2021-07-05 13:25:03 +00:00
options = append ( options , grpc . Creds ( credentials . NewTLS ( config . GetTLSConfig ( tls . WithNextProto ( "h2" ) ) ) ) )
2021-03-14 15:02:07 +00:00
}
2021-07-05 13:25:03 +00: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 15:02:07 +00: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
}
}
2023-03-26 05:58:19 +00:00
newError ( "gRPC listen for service name `" + grpcSettings . getServiceName ( ) + "` tun `" + grpcSettings . getTunStreamName ( ) + "` multi tun `" + grpcSettings . getTunMultiStreamName ( ) + "`" ) . AtDebug ( ) . WriteToLog ( )
encoding . RegisterGRPCServiceServerX ( s , listener , grpcSettings . getServiceName ( ) , grpcSettings . getTunStreamName ( ) , grpcSettings . getTunMultiStreamName ( ) )
2021-03-14 15:02:07 +00:00
2023-02-27 19:52:01 +00:00
if config := reality . ConfigFromStreamSettings ( settings ) ; config != nil {
streamListener = goreality . NewListener ( streamListener , config . GetREALITYConfig ( ) )
}
2021-03-14 15:02:07 +00:00
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 ) )
}