1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "remoting/host/zombie_host_detector.h"
6 
7 #include "base/check.h"
8 #include "base/logging.h"
9 #include "net/base/network_change_notifier.h"
10 
11 namespace {
12 
IsMaxDurationExceeded(base::TimeTicks event_time,base::TimeDelta max_duration,const std::string & event_name)13 bool IsMaxDurationExceeded(base::TimeTicks event_time,
14                            base::TimeDelta max_duration,
15                            const std::string& event_name) {
16   if (event_time.is_null()) {
17     VLOG(1) << "Last " << event_name << " is null.";
18     return false;
19   }
20   base::TimeDelta event_duration = base::TimeTicks::Now() - event_time;
21   DCHECK_GE(event_duration, base::TimeDelta()) << "Event duration is negative.";
22   bool is_exceeded = event_duration > max_duration;
23   if (is_exceeded) {
24     LOG(ERROR) << "Last " << event_name << " happened " << event_duration
25                << " ago, exceeding max duration of " << max_duration;
26   } else {
27     VLOG(1) << "Last " << event_name << " happened " << event_duration
28             << " ago.";
29   }
30   return is_exceeded;
31 }
32 
33 }  // namespace
34 
35 namespace remoting {
36 
37 // static
38 constexpr base::TimeDelta ZombieHostDetector::kZombieStateDetectionInterval;
39 constexpr base::TimeDelta ZombieHostDetector::kMaxHeartbeatInterval;
40 constexpr base::TimeDelta ZombieHostDetector::kMaxSignalingActiveInterval;
41 
ZombieHostDetector(base::OnceClosure on_zombie_state_detected)42 ZombieHostDetector::ZombieHostDetector(
43     base::OnceClosure on_zombie_state_detected) {
44   DCHECK(on_zombie_state_detected);
45 
46   on_zombie_state_detected_ = std::move(on_zombie_state_detected);
47 }
48 
49 ZombieHostDetector::~ZombieHostDetector() = default;
50 
Start()51 void ZombieHostDetector::Start() {
52   check_zombie_state_timer_.Start(FROM_HERE, kZombieStateDetectionInterval,
53                                   this, &ZombieHostDetector::CheckZombieState);
54 }
55 
OnHeartbeatSent()56 void ZombieHostDetector::OnHeartbeatSent() {
57   last_heartbeat_time_ = base::TimeTicks::Now();
58 }
59 
OnSignalingActive()60 void ZombieHostDetector::OnSignalingActive() {
61   last_signaling_active_time_ = base::TimeTicks::Now();
62 }
63 
GetNextDetectionTime() const64 base::TimeTicks ZombieHostDetector::GetNextDetectionTime() const {
65   return check_zombie_state_timer_.desired_run_time();
66 }
67 
CheckZombieState()68 void ZombieHostDetector::CheckZombieState() {
69   VLOG(1) << "Detecting zombie state...";
70 
71   if (net::NetworkChangeNotifier::GetConnectionType() ==
72       net::NetworkChangeNotifier::CONNECTION_NONE) {
73     // The host shouldn't be considered in zombie state if it has no connection.
74     VLOG(1) << "No internet connectivity. Skipping zombie state check...";
75     previously_offline_ = true;
76     return;
77   }
78 
79   if (previously_offline_) {
80     // If the host was previously offline, heartbeat/signaling might not have
81     // happened at this point due to backoff. Reset them to |now| to allow them
82     // to come through.
83 
84     previously_offline_ = false;
85 
86     VLOG(1) << "Host is going online. Previous heartbeat time: "
87             << last_heartbeat_time_ << ", previous signaling active time: "
88             << last_signaling_active_time_ << ". These will be reset to |now|.";
89 
90     // Don't reset if they are null, which happens when the first
91     // heartbeat/signaling attempt has not succeeded yet.
92     if (!last_heartbeat_time_.is_null()) {
93       OnHeartbeatSent();
94     }
95     if (!last_signaling_active_time_.is_null()) {
96       OnSignalingActive();
97     }
98     return;
99   }
100 
101   if (IsMaxDurationExceeded(last_heartbeat_time_, kMaxHeartbeatInterval,
102                             "heartbeat") ||
103       IsMaxDurationExceeded(last_signaling_active_time_,
104                             kMaxSignalingActiveInterval,
105                             "signaling activity")) {
106     LOG(ERROR) << "Host zombie state detected.";
107     check_zombie_state_timer_.Stop();
108     std::move(on_zombie_state_detected_).Run();
109     return;
110   }
111 
112   VLOG(1) << "No zombie state detected.";
113 }
114 
115 }  // namespace remoting
116