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