dial.go 3.4 KB

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