ping.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package router
  2. import (
  3. "context"
  4. "net/http"
  5. "time"
  6. "github.com/v2fly/v2ray-core/v4/common/net"
  7. "github.com/v2fly/v2ray-core/v4/common/session"
  8. "github.com/v2fly/v2ray-core/v4/features/routing"
  9. )
  10. type pingClient struct {
  11. destination string
  12. httpClient *http.Client
  13. }
  14. func newPingClient(destination string, timeout time.Duration, handler string, dispatcher routing.Dispatcher) *pingClient {
  15. return &pingClient{
  16. destination: destination,
  17. httpClient: newHTTPClient(handler, dispatcher, timeout),
  18. }
  19. }
  20. func newDirectPingClient(destination string, timeout time.Duration) *pingClient {
  21. return &pingClient{
  22. destination: destination,
  23. httpClient: &http.Client{Timeout: timeout},
  24. }
  25. }
  26. func newHTTPClient(handler string, dispatcher routing.Dispatcher, timeout time.Duration) *http.Client {
  27. tr := &http.Transport{
  28. DisableKeepAlives: true,
  29. DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
  30. dest, err := net.ParseDestination(network + ":" + addr)
  31. if err != nil {
  32. return nil, err
  33. }
  34. h := &session.Handler{
  35. Tag: handler,
  36. }
  37. ctx = session.ContextWithHandler(ctx, h)
  38. link, err := dispatcher.Dispatch(ctx, dest)
  39. if err != nil {
  40. return nil, err
  41. }
  42. return net.NewConnection(
  43. net.ConnectionInputMulti(link.Writer),
  44. net.ConnectionOutputMulti(link.Reader),
  45. ), nil
  46. },
  47. }
  48. return &http.Client{
  49. Transport: tr,
  50. Timeout: timeout,
  51. // don't follow redirect
  52. CheckRedirect: func(req *http.Request, via []*http.Request) error {
  53. return http.ErrUseLastResponse
  54. },
  55. }
  56. }
  57. // MeasureDelay returns the delay time of the request to dest
  58. func (s *pingClient) MeasureDelay() (time.Duration, error) {
  59. if s.httpClient == nil {
  60. panic("pingClient no initialized")
  61. }
  62. req, err := http.NewRequest(http.MethodHead, s.destination, nil)
  63. if err != nil {
  64. return rttFailed, err
  65. }
  66. start := time.Now()
  67. resp, err := s.httpClient.Do(req)
  68. if err != nil {
  69. return rttFailed, err
  70. }
  71. // don't wait for body
  72. resp.Body.Close()
  73. return time.Since(start), nil
  74. }