ping.go 1.9 KB

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