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