client.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package shadowsocks
  2. import (
  3. "errors"
  4. "sync"
  5. "v2ray.com/core/common/alloc"
  6. v2io "v2ray.com/core/common/io"
  7. "v2ray.com/core/common/log"
  8. v2net "v2ray.com/core/common/net"
  9. "v2ray.com/core/common/protocol"
  10. "v2ray.com/core/common/retry"
  11. "v2ray.com/core/proxy"
  12. "v2ray.com/core/transport/internet"
  13. "v2ray.com/core/transport/ray"
  14. )
  15. type Client struct {
  16. serverPicker protocol.ServerPicker
  17. meta *proxy.OutboundHandlerMeta
  18. }
  19. func (this *Client) Dispatch(destination v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error {
  20. defer payload.Release()
  21. defer ray.OutboundInput().Release()
  22. defer ray.OutboundOutput().Close()
  23. network := destination.Network
  24. var server *protocol.ServerSpec
  25. var conn internet.Connection
  26. err := retry.Timed(5, 100).On(func() error {
  27. server = this.serverPicker.PickServer()
  28. dest := server.Destination()
  29. dest.Network = network
  30. rawConn, err := internet.Dial(this.meta.Address, dest, this.meta.StreamSettings)
  31. if err != nil {
  32. return err
  33. }
  34. conn = rawConn
  35. return nil
  36. })
  37. if err != nil {
  38. return errors.New("Shadowsocks|Client: Failed to find an available destination:" + err.Error())
  39. }
  40. log.Info("Shadowsocks|Client: Tunneling request to ", destination, " via ", server.Destination())
  41. request := &protocol.RequestHeader{
  42. Version: Version,
  43. Address: destination.Address,
  44. Port: destination.Port,
  45. }
  46. if destination.Network == v2net.Network_TCP {
  47. request.Command = protocol.RequestCommandTCP
  48. } else {
  49. request.Command = protocol.RequestCommandUDP
  50. }
  51. user := server.PickUser()
  52. rawAccount, err := user.GetTypedAccount()
  53. if err != nil {
  54. return errors.New("Shadowsocks|Client: Failed to get a valid user account: " + err.Error())
  55. }
  56. account := rawAccount.(*ShadowsocksAccount)
  57. request.User = user
  58. if account.OneTimeAuth == Account_Auto || account.OneTimeAuth == Account_Enabled {
  59. request.Option |= RequestOptionOneTimeAuth
  60. }
  61. if request.Command == protocol.RequestCommandTCP {
  62. bufferedWriter := v2io.NewBufferedWriter(conn)
  63. defer bufferedWriter.Release()
  64. bodyWriter, err := WriteTCPRequest(request, bufferedWriter)
  65. defer bodyWriter.Release()
  66. if err != nil {
  67. return errors.New("Shadowsock|Client: Failed to write request: " + err.Error())
  68. }
  69. if err := bodyWriter.Write(payload); err != nil {
  70. return errors.New("Shadowsocks|Client: Failed to write payload: " + err.Error())
  71. }
  72. bufferedWriter.SetCached(false)
  73. v2io.Pipe(ray.OutboundInput(), bodyWriter)
  74. var responseMutex sync.Mutex
  75. responseMutex.Lock()
  76. go func() {
  77. defer responseMutex.Unlock()
  78. responseReader, err := ReadTCPResponse(user, conn)
  79. if err != nil {
  80. log.Warning("Shadowsocks|Client: Failed to read response: " + err.Error())
  81. return
  82. }
  83. v2io.Pipe(responseReader, ray.OutboundOutput())
  84. }()
  85. responseMutex.Lock()
  86. }
  87. if request.Command == protocol.RequestCommandUDP {
  88. writer := &UDPWriter{
  89. Writer: conn,
  90. Request: request,
  91. }
  92. if err := writer.Write(payload); err != nil {
  93. return errors.New("Shadowsocks|Client: Failed to write payload: " + err.Error())
  94. }
  95. v2io.Pipe(ray.OutboundInput(), writer)
  96. timedReader := v2net.NewTimeOutReader(16, conn)
  97. var responseMutex sync.Mutex
  98. responseMutex.Lock()
  99. go func() {
  100. defer responseMutex.Unlock()
  101. reader := &UDPReader{
  102. Reader: timedReader,
  103. User: user,
  104. }
  105. v2io.Pipe(reader, ray.OutboundOutput())
  106. }()
  107. responseMutex.Lock()
  108. }
  109. return nil
  110. }