dialer.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package websocket
  2. import (
  3. "context"
  4. "time"
  5. "github.com/gorilla/websocket"
  6. "v2ray.com/core/app/log"
  7. "v2ray.com/core/common"
  8. "v2ray.com/core/common/net"
  9. "v2ray.com/core/transport/internet"
  10. "v2ray.com/core/transport/internet/tls"
  11. )
  12. // Dial dials a WebSocket connection to the given destination.
  13. func Dial(ctx context.Context, dest net.Destination) (internet.Connection, error) {
  14. log.Trace(newError("creating connection to ", dest))
  15. conn, err := dialWebsocket(ctx, dest)
  16. if err != nil {
  17. return nil, newError("failed to dial WebSocket").Base(err)
  18. }
  19. return internet.Connection(conn), nil
  20. }
  21. func init() {
  22. common.Must(internet.RegisterTransportDialer(internet.TransportProtocol_WebSocket, Dial))
  23. }
  24. func dialWebsocket(ctx context.Context, dest net.Destination) (net.Conn, error) {
  25. src := internet.DialerSourceFromContext(ctx)
  26. wsSettings := internet.TransportSettingsFromContext(ctx).(*Config)
  27. dialer := &websocket.Dialer{
  28. NetDial: func(network, addr string) (net.Conn, error) {
  29. return internet.DialSystem(ctx, src, dest)
  30. },
  31. ReadBufferSize: 32 * 1024,
  32. WriteBufferSize: 32 * 1024,
  33. HandshakeTimeout: time.Second * 8,
  34. }
  35. protocol := "ws"
  36. if securitySettings := internet.SecuritySettingsFromContext(ctx); securitySettings != nil {
  37. tlsConfig, ok := securitySettings.(*tls.Config)
  38. if ok {
  39. protocol = "wss"
  40. dialer.TLSClientConfig = tlsConfig.GetTLSConfig()
  41. if dest.Address.Family().IsDomain() {
  42. dialer.TLSClientConfig.ServerName = dest.Address.Domain()
  43. }
  44. }
  45. }
  46. host := dest.NetAddr()
  47. if (protocol == "ws" && dest.Port == 80) || (protocol == "wss" && dest.Port == 443) {
  48. host = dest.Address.String()
  49. }
  50. uri := protocol + "://" + host + wsSettings.GetNormailzedPath()
  51. conn, resp, err := dialer.Dial(uri, wsSettings.GetRequestHeader())
  52. if err != nil {
  53. var reason string
  54. if resp != nil {
  55. reason = resp.Status
  56. }
  57. return nil, newError("failed to dial to (", uri, "): ", reason).Base(err)
  58. }
  59. return newConnection(conn), nil
  60. }