ping.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package burst
  2. import (
  3. "context"
  4. "io"
  5. "net/http"
  6. "time"
  7. "github.com/xtls/xray-core/common/net"
  8. "github.com/xtls/xray-core/common/utils"
  9. "github.com/xtls/xray-core/features/routing"
  10. "github.com/xtls/xray-core/transport/internet/tagged"
  11. )
  12. type pingClient struct {
  13. destination string
  14. httpClient *http.Client
  15. }
  16. func newPingClient(ctx context.Context, dispatcher routing.Dispatcher, destination string, timeout time.Duration, handler string) *pingClient {
  17. return &pingClient{
  18. destination: destination,
  19. httpClient: newHTTPClient(ctx, dispatcher, handler, timeout),
  20. }
  21. }
  22. func newDirectPingClient(destination string, timeout time.Duration) *pingClient {
  23. return &pingClient{
  24. destination: destination,
  25. httpClient: &http.Client{Timeout: timeout},
  26. }
  27. }
  28. func newHTTPClient(ctxv context.Context, dispatcher routing.Dispatcher, handler string, timeout time.Duration) *http.Client {
  29. tr := &http.Transport{
  30. DisableKeepAlives: true,
  31. DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
  32. dest, err := net.ParseDestination(network + ":" + addr)
  33. if err != nil {
  34. return nil, err
  35. }
  36. return tagged.Dialer(ctxv, dispatcher, dest, handler)
  37. },
  38. }
  39. return &http.Client{
  40. Transport: tr,
  41. Timeout: timeout,
  42. // don't follow redirect
  43. CheckRedirect: func(req *http.Request, via []*http.Request) error {
  44. return http.ErrUseLastResponse
  45. },
  46. }
  47. }
  48. // MeasureDelay returns the delay time of the request to dest
  49. func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
  50. if s.httpClient == nil {
  51. panic("pingClient not initialized")
  52. }
  53. req, err := http.NewRequest(httpMethod, s.destination, nil)
  54. if err != nil {
  55. return rttFailed, err
  56. }
  57. utils.TryDefaultHeadersWith(req.Header, "nav")
  58. start := time.Now()
  59. resp, err := s.httpClient.Do(req)
  60. if err != nil {
  61. return rttFailed, err
  62. }
  63. if httpMethod == http.MethodGet {
  64. _, err = io.Copy(io.Discard, resp.Body)
  65. if err != nil {
  66. return rttFailed, err
  67. }
  68. }
  69. resp.Body.Close()
  70. return time.Since(start), nil
  71. }