dial.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. //go:build !confonly
  2. // +build !confonly
  3. package grpc
  4. import (
  5. "context"
  6. gonet "net"
  7. "sync"
  8. "time"
  9. "google.golang.org/grpc"
  10. "google.golang.org/grpc/backoff"
  11. "google.golang.org/grpc/connectivity"
  12. "google.golang.org/grpc/credentials"
  13. "google.golang.org/grpc/credentials/insecure"
  14. core "github.com/v2fly/v2ray-core/v5"
  15. "github.com/v2fly/v2ray-core/v5/common"
  16. "github.com/v2fly/v2ray-core/v5/common/net"
  17. "github.com/v2fly/v2ray-core/v5/common/session"
  18. "github.com/v2fly/v2ray-core/v5/transport/internet"
  19. "github.com/v2fly/v2ray-core/v5/transport/internet/grpc/encoding"
  20. "github.com/v2fly/v2ray-core/v5/transport/internet/tls"
  21. )
  22. func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
  23. newError("creating connection to ", dest).WriteToLog(session.ExportIDToError(ctx))
  24. conn, err := dialgRPC(ctx, dest, streamSettings)
  25. if err != nil {
  26. return nil, newError("failed to dial Grpc").Base(err)
  27. }
  28. return internet.Connection(conn), nil
  29. }
  30. func init() {
  31. common.Must(internet.RegisterTransportDialer(protocolName, Dial))
  32. }
  33. type dialerCanceller func()
  34. var (
  35. globalDialerMap map[net.Destination]*grpc.ClientConn
  36. globalDialerAccess sync.Mutex
  37. )
  38. func dialgRPC(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {
  39. grpcSettings := streamSettings.ProtocolSettings.(*Config)
  40. config := tls.ConfigFromStreamSettings(streamSettings)
  41. transportCredentials := insecure.NewCredentials()
  42. if config != nil {
  43. transportCredentials = credentials.NewTLS(config.GetTLSConfig(tls.WithDestination(dest)))
  44. }
  45. dialOption := grpc.WithTransportCredentials(transportCredentials)
  46. conn, canceller, err := getGrpcClient(ctx, dest, dialOption, streamSettings)
  47. if err != nil {
  48. return nil, newError("Cannot dial grpc").Base(err)
  49. }
  50. client := encoding.NewGunServiceClient(conn)
  51. gunService, err := client.(encoding.GunServiceClientX).TunCustomName(ctx, grpcSettings.ServiceName)
  52. if err != nil {
  53. canceller()
  54. return nil, newError("Cannot dial grpc").Base(err)
  55. }
  56. return encoding.NewGunConn(gunService, nil), nil
  57. }
  58. func getGrpcClient(ctx context.Context, dest net.Destination, dialOption grpc.DialOption, streamSettings *internet.MemoryStreamConfig) (*grpc.ClientConn, dialerCanceller, error) {
  59. globalDialerAccess.Lock()
  60. defer globalDialerAccess.Unlock()
  61. if globalDialerMap == nil {
  62. globalDialerMap = make(map[net.Destination]*grpc.ClientConn)
  63. }
  64. canceller := func() {
  65. globalDialerAccess.Lock()
  66. defer globalDialerAccess.Unlock()
  67. delete(globalDialerMap, dest)
  68. }
  69. // TODO Should support chain proxy to the same destination
  70. if client, found := globalDialerMap[dest]; found && client.GetState() != connectivity.Shutdown {
  71. return client, canceller, nil
  72. }
  73. conn, err := grpc.Dial(
  74. dest.Address.String()+":"+dest.Port.String(),
  75. dialOption,
  76. grpc.WithConnectParams(grpc.ConnectParams{
  77. Backoff: backoff.Config{
  78. BaseDelay: 500 * time.Millisecond,
  79. Multiplier: 1.5,
  80. Jitter: 0.2,
  81. MaxDelay: 19 * time.Second,
  82. },
  83. MinConnectTimeout: 5 * time.Second,
  84. }),
  85. grpc.WithContextDialer(func(ctxGrpc context.Context, s string) (gonet.Conn, error) {
  86. rawHost, rawPort, err := net.SplitHostPort(s)
  87. if err != nil {
  88. return nil, err
  89. }
  90. if len(rawPort) == 0 {
  91. rawPort = "443"
  92. }
  93. port, err := net.PortFromString(rawPort)
  94. if err != nil {
  95. return nil, err
  96. }
  97. address := net.ParseAddress(rawHost)
  98. detachedContext := core.ToBackgroundDetachedContext(ctx)
  99. return internet.DialSystem(detachedContext, net.TCPDestination(address, port), streamSettings.SocketSettings)
  100. }),
  101. )
  102. globalDialerMap[dest] = conn
  103. return conn, canceller, err
  104. }