github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/app/observatory/burst/ping.go (about)

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