dialer.go 1.9 KB

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