|
|
@@ -1302,3 +1302,59 @@ func (c *Direct) SetDNS(ctx context.Context, req *tailcfg.SetDNSRequest) error {
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
+
|
|
|
+// tsmpPing sends a Ping to pr.IP, and sends an http request back to pr.URL
|
|
|
+// with ping response data.
|
|
|
+func tsmpPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, pinger Pinger) error {
|
|
|
+ var err error
|
|
|
+ if pr.URL == "" {
|
|
|
+ return errors.New("invalid PingRequest with no URL")
|
|
|
+ }
|
|
|
+ if pr.IP.IsZero() {
|
|
|
+ return fmt.Errorf("PingRequest with no proper IP got %v", pr.IP)
|
|
|
+ }
|
|
|
+ if !strings.Contains(pr.Types, "TSMP") {
|
|
|
+ return fmt.Errorf("PingRequest with no TSMP in Types, got : %v", pr.Types)
|
|
|
+ }
|
|
|
+
|
|
|
+ now := time.Now()
|
|
|
+ pinger.Ping(pr.IP, true, func(res *ipnstate.PingResult) {
|
|
|
+ // Currently does not check for error since we just return if it fails.
|
|
|
+ err = postPingResult(now, logf, c, pr, res)
|
|
|
+ })
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func postPingResult(now time.Time, logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, res *ipnstate.PingResult) error {
|
|
|
+ if res.Err != "" {
|
|
|
+ return errors.New(res.Err)
|
|
|
+ }
|
|
|
+ duration := time.Since(now)
|
|
|
+ if pr.Log {
|
|
|
+ logf("TSMP ping to %v completed in %v seconds. pinger.Ping took %v seconds", pr.IP, res.LatencySeconds, duration.Seconds())
|
|
|
+ }
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ jsonPingRes, err := json.Marshal(res)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ // Send the results of the Ping, back to control URL.
|
|
|
+ req, err := http.NewRequestWithContext(ctx, "POST", pr.URL, bytes.NewBuffer(jsonPingRes))
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("http.NewRequestWithContext(%q): %w", pr.URL, err)
|
|
|
+ }
|
|
|
+ if pr.Log {
|
|
|
+ logf("tsmpPing: sending ping results to %v ...", pr.URL)
|
|
|
+ }
|
|
|
+ t0 := time.Now()
|
|
|
+ _, err = c.Do(req)
|
|
|
+ d := time.Since(t0).Round(time.Millisecond)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("tsmpPing error: %w to %v (after %v)", err, pr.URL, d)
|
|
|
+ } else if pr.Log {
|
|
|
+ logf("tsmpPing complete to %v (after %v)", pr.URL, d)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|