Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: remoting/host/heartbeat_sender.cc

Issue 2915193003: Add heartbeat timeout. (Closed)
Patch Set: 30 seconds Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/host/heartbeat_sender.h ('k') | remoting/host/heartbeat_sender_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/heartbeat_sender.h" 5 #include "remoting/host/heartbeat_sender.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 30 matching lines...) Expand all
41 const char kHostOperatingSystemNameTag[] = "host-os-name"; 41 const char kHostOperatingSystemNameTag[] = "host-os-name";
42 const char kHostOperatingSystemVersionTag[] = "host-os-version"; 42 const char kHostOperatingSystemVersionTag[] = "host-os-version";
43 43
44 const char kErrorTag[] = "error"; 44 const char kErrorTag[] = "error";
45 const char kNotFoundTag[] = "item-not-found"; 45 const char kNotFoundTag[] = "item-not-found";
46 46
47 const char kHeartbeatResultTag[] = "heartbeat-result"; 47 const char kHeartbeatResultTag[] = "heartbeat-result";
48 const char kSetIntervalTag[] = "set-interval"; 48 const char kSetIntervalTag[] = "set-interval";
49 const char kExpectedSequenceIdTag[] = "expected-sequence-id"; 49 const char kExpectedSequenceIdTag[] = "expected-sequence-id";
50 50
51 const int64_t kDefaultHeartbeatIntervalMs = 5 * 60 * 1000; // 5 minutes. 51 constexpr base::TimeDelta kDefaultHeartbeatInterval =
52 const int64_t kResendDelayMs = 10 * 1000; // 10 seconds. 52 base::TimeDelta::FromMinutes(5);
53 const int64_t kResendDelayOnHostNotFoundMs = 10 * 1000; // 10 seconds. 53 constexpr base::TimeDelta kHeartbeatResponseTimeout =
54 base::TimeDelta::FromSeconds(30);
55 constexpr base::TimeDelta kResendDelay = base::TimeDelta::FromSeconds(10);
56 constexpr base::TimeDelta kResendDelayOnHostNotFound =
57 base::TimeDelta::FromSeconds(10);
58
54 const int kMaxResendOnHostNotFoundCount = 12; // 2 minutes (12 x 10 seconds). 59 const int kMaxResendOnHostNotFoundCount = 12; // 2 minutes (12 x 10 seconds).
60 const int kMaxHeartbeatTimeouts = 2;
55 61
56 } // namespace 62 } // namespace
57 63
58 HeartbeatSender::HeartbeatSender( 64 HeartbeatSender::HeartbeatSender(
59 const base::Closure& on_heartbeat_successful_callback, 65 const base::Closure& on_heartbeat_successful_callback,
60 const base::Closure& on_unknown_host_id_error, 66 const base::Closure& on_unknown_host_id_error,
61 const std::string& host_id, 67 const std::string& host_id,
62 SignalStrategy* signal_strategy, 68 SignalStrategy* signal_strategy,
63 const scoped_refptr<const RsaKeyPair>& host_key_pair, 69 const scoped_refptr<const RsaKeyPair>& host_key_pair,
64 const std::string& directory_bot_jid) 70 const std::string& directory_bot_jid)
65 : on_heartbeat_successful_callback_(on_heartbeat_successful_callback), 71 : on_heartbeat_successful_callback_(on_heartbeat_successful_callback),
66 on_unknown_host_id_error_(on_unknown_host_id_error), 72 on_unknown_host_id_error_(on_unknown_host_id_error),
67 host_id_(host_id), 73 host_id_(host_id),
68 signal_strategy_(signal_strategy), 74 signal_strategy_(signal_strategy),
69 host_key_pair_(host_key_pair), 75 host_key_pair_(host_key_pair),
70 directory_bot_jid_(directory_bot_jid), 76 directory_bot_jid_(directory_bot_jid),
71 interval_ms_(kDefaultHeartbeatIntervalMs), 77 interval_(kDefaultHeartbeatInterval) {
72 sequence_id_(0),
73 sequence_id_was_set_(false),
74 sequence_id_recent_set_num_(0),
75 heartbeat_succeeded_(false),
76 failed_startup_heartbeat_count_(0) {
77 DCHECK(signal_strategy_); 78 DCHECK(signal_strategy_);
78 DCHECK(host_key_pair_.get()); 79 DCHECK(host_key_pair_.get());
79 DCHECK(thread_checker_.CalledOnValidThread()); 80 DCHECK(thread_checker_.CalledOnValidThread());
80 81
81 signal_strategy_->AddListener(this); 82 signal_strategy_->AddListener(this);
82 83
83 // Start heartbeats if the |signal_strategy_| is already connected. 84 // Start heartbeats if the |signal_strategy_| is already connected.
84 OnSignalStrategyStateChange(signal_strategy_->GetState()); 85 OnSignalStrategyStateChange(signal_strategy_->GetState());
85 } 86 }
86 87
87 HeartbeatSender::~HeartbeatSender() { 88 HeartbeatSender::~HeartbeatSender() {
88 DCHECK(thread_checker_.CalledOnValidThread()); 89 DCHECK(thread_checker_.CalledOnValidThread());
89 signal_strategy_->RemoveListener(this); 90 signal_strategy_->RemoveListener(this);
90 } 91 }
91 92
92 void HeartbeatSender::OnSignalStrategyStateChange(SignalStrategy::State state) { 93 void HeartbeatSender::OnSignalStrategyStateChange(SignalStrategy::State state) {
93 DCHECK(thread_checker_.CalledOnValidThread()); 94 DCHECK(thread_checker_.CalledOnValidThread());
94 if (state == SignalStrategy::CONNECTED) { 95 if (state == SignalStrategy::CONNECTED) {
95 iq_sender_.reset(new IqSender(signal_strategy_)); 96 iq_sender_ = base::MakeUnique<IqSender>(signal_strategy_);
96 SendStanza(); 97 SendStanza();
97 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(interval_ms_), 98 timer_.Start(FROM_HERE, interval_, this, &HeartbeatSender::SendStanza);
98 this, &HeartbeatSender::SendStanza);
99 } else if (state == SignalStrategy::DISCONNECTED) { 99 } else if (state == SignalStrategy::DISCONNECTED) {
100 request_.reset(); 100 request_.reset();
101 iq_sender_.reset(); 101 iq_sender_.reset();
102 timer_.Stop(); 102 timer_.Stop();
103 timer_resend_.Stop(); 103 timer_resend_.Stop();
104 } 104 }
105 } 105 }
106 106
107 bool HeartbeatSender::OnSignalStrategyIncomingStanza( 107 bool HeartbeatSender::OnSignalStrategyIncomingStanza(
108 const buzz::XmlElement* stanza) { 108 const buzz::XmlElement* stanza) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 DoSendStanza(); 162 DoSendStanza();
163 } 163 }
164 164
165 void HeartbeatSender::DoSendStanza() { 165 void HeartbeatSender::DoSendStanza() {
166 DCHECK(thread_checker_.CalledOnValidThread()); 166 DCHECK(thread_checker_.CalledOnValidThread());
167 DCHECK(signal_strategy_->GetState() == SignalStrategy::CONNECTED); 167 DCHECK(signal_strategy_->GetState() == SignalStrategy::CONNECTED);
168 VLOG(1) << "Sending heartbeat stanza to " << directory_bot_jid_; 168 VLOG(1) << "Sending heartbeat stanza to " << directory_bot_jid_;
169 169
170 request_ = iq_sender_->SendIq( 170 request_ = iq_sender_->SendIq(
171 buzz::STR_SET, directory_bot_jid_, CreateHeartbeatMessage(), 171 buzz::STR_SET, directory_bot_jid_, CreateHeartbeatMessage(),
172 base::Bind(&HeartbeatSender::ProcessResponse, 172 base::Bind(&HeartbeatSender::ProcessResponse, base::Unretained(this),
173 base::Unretained(this),
174 !host_offline_reason_.empty())); 173 !host_offline_reason_.empty()));
174 request_->SetTimeout(kHeartbeatResponseTimeout);
175 ++sequence_id_; 175 ++sequence_id_;
176 } 176 }
177 177
178 void HeartbeatSender::ProcessResponse( 178 void HeartbeatSender::ProcessResponse(bool is_offline_heartbeat_response,
179 bool is_offline_heartbeat_response, 179 IqRequest* request,
180 IqRequest* request, 180 const XmlElement* response) {
181 const XmlElement* response) {
182 DCHECK(thread_checker_.CalledOnValidThread()); 181 DCHECK(thread_checker_.CalledOnValidThread());
183 182
183 if (!response) {
184 timed_out_heartbeats_count_++;
185 if (timed_out_heartbeats_count_ >= kMaxHeartbeatTimeouts) {
186 LOG(ERROR) << "Heartbeat timed out. Reconnecting XMPP.";
187 timed_out_heartbeats_count_ = 0;
188 // SignalingConnector will reconnect SignalStrategy.
189 signal_strategy_->Disconnect();
190 } else {
191 LOG(ERROR) << "Heartbeat timed out.";
192 }
193 return;
194 } else {
195 timed_out_heartbeats_count_ = 0;
196 }
197
184 std::string type = response->Attr(buzz::QN_TYPE); 198 std::string type = response->Attr(buzz::QN_TYPE);
185 if (type == buzz::STR_ERROR) { 199 if (type == buzz::STR_ERROR) {
186 const XmlElement* error_element = 200 const XmlElement* error_element =
187 response->FirstNamed(QName(buzz::NS_CLIENT, kErrorTag)); 201 response->FirstNamed(QName(buzz::NS_CLIENT, kErrorTag));
188 if (error_element) { 202 if (error_element) {
189 if (error_element->FirstNamed(QName(buzz::NS_STANZA, kNotFoundTag))) { 203 if (error_element->FirstNamed(QName(buzz::NS_STANZA, kNotFoundTag))) {
190 LOG(ERROR) << "Received error: Host ID not found"; 204 LOG(ERROR) << "Received error: Host ID not found";
191 // If the host was registered immediately before it sends a heartbeat, 205 // If the host was registered immediately before it sends a heartbeat,
192 // then server-side latency may prevent the server recognizing the 206 // then server-side latency may prevent the server recognizing the
193 // host ID in the heartbeat. So even if all of the first few heartbeats 207 // host ID in the heartbeat. So even if all of the first few heartbeats
194 // get a "host ID not found" error, that's not a good enough reason to 208 // get a "host ID not found" error, that's not a good enough reason to
195 // exit. 209 // exit.
196 failed_startup_heartbeat_count_++; 210 failed_startup_heartbeat_count_++;
197 if (!heartbeat_succeeded_ && (failed_startup_heartbeat_count_ <= 211 if (!heartbeat_succeeded_ && (failed_startup_heartbeat_count_ <=
198 kMaxResendOnHostNotFoundCount)) { 212 kMaxResendOnHostNotFoundCount)) {
199 timer_resend_.Start(FROM_HERE, 213 timer_resend_.Start(FROM_HERE, kResendDelayOnHostNotFound, this,
200 base::TimeDelta::FromMilliseconds(
201 kResendDelayOnHostNotFoundMs),
202 this,
203 &HeartbeatSender::ResendStanza); 214 &HeartbeatSender::ResendStanza);
204 return; 215 return;
205 } 216 }
206 on_unknown_host_id_error_.Run(); 217 on_unknown_host_id_error_.Run();
207 return; 218 return;
208 } 219 }
209 } 220 }
210 221
211 LOG(ERROR) << "Received error in response to heartbeat: " 222 LOG(ERROR) << "Received error in response to heartbeat: "
212 << response->Str(); 223 << response->Str();
213 return; 224 return;
214 } 225 }
215 226
216 // This method must only be called for error or result stanzas. 227 // This method must only be called for error or result stanzas.
217 DCHECK_EQ(std::string(buzz::STR_RESULT), type); 228 DCHECK_EQ(std::string(buzz::STR_RESULT), type);
218 229
219 const XmlElement* result_element = 230 const XmlElement* result_element =
220 response->FirstNamed(QName(kChromotingXmlNamespace, kHeartbeatResultTag)); 231 response->FirstNamed(QName(kChromotingXmlNamespace, kHeartbeatResultTag));
221 if (result_element) { 232 if (result_element) {
222 const XmlElement* set_interval_element = 233 const XmlElement* set_interval_element =
223 result_element->FirstNamed(QName(kChromotingXmlNamespace, 234 result_element->FirstNamed(QName(kChromotingXmlNamespace,
224 kSetIntervalTag)); 235 kSetIntervalTag));
225 if (set_interval_element) { 236 if (set_interval_element) {
226 const std::string& interval_str = set_interval_element->BodyText(); 237 const std::string& interval_str = set_interval_element->BodyText();
227 int interval; 238 int interval_seconds;
228 if (!base::StringToInt(interval_str, &interval) || interval <= 0) { 239 if (!base::StringToInt(interval_str, &interval_seconds) ||
240 interval_seconds <= 0) {
229 LOG(ERROR) << "Received invalid set-interval: " 241 LOG(ERROR) << "Received invalid set-interval: "
230 << set_interval_element->Str(); 242 << set_interval_element->Str();
231 } else { 243 } else {
232 SetInterval(interval * base::Time::kMillisecondsPerSecond); 244 SetInterval(base::TimeDelta::FromSeconds(interval_seconds));
233 } 245 }
234 } 246 }
235 247
236 bool did_set_sequence_id = false; 248 bool did_set_sequence_id = false;
237 const XmlElement* expected_sequence_id_element = 249 const XmlElement* expected_sequence_id_element =
238 result_element->FirstNamed(QName(kChromotingXmlNamespace, 250 result_element->FirstNamed(QName(kChromotingXmlNamespace,
239 kExpectedSequenceIdTag)); 251 kExpectedSequenceIdTag));
240 if (expected_sequence_id_element) { 252 if (expected_sequence_id_element) {
241 // The sequence ID sent in the previous heartbeat was not what the server 253 // The sequence ID sent in the previous heartbeat was not what the server
242 // expected, so send another heartbeat with the expected sequence ID. 254 // expected, so send another heartbeat with the expected sequence ID.
(...skipping 20 matching lines...) Expand all
263 heartbeat_succeeded_ = true; 275 heartbeat_succeeded_ = true;
264 276
265 // Notify caller of SetHostOfflineReason that we got an ack. 277 // Notify caller of SetHostOfflineReason that we got an ack.
266 if (is_offline_heartbeat_response) { 278 if (is_offline_heartbeat_response) {
267 OnHostOfflineReasonAck(); 279 OnHostOfflineReasonAck();
268 } 280 }
269 } 281 }
270 } 282 }
271 } 283 }
272 284
273 void HeartbeatSender::SetInterval(int interval) { 285 void HeartbeatSender::SetInterval(base::TimeDelta interval) {
274 if (interval != interval_ms_) { 286 if (interval != interval_) {
275 interval_ms_ = interval; 287 interval_ = interval;
276 288
277 // Restart the timer with the new interval. 289 // Restart the timer with the new interval.
278 if (timer_.IsRunning()) { 290 if (timer_.IsRunning()) {
279 timer_.Stop(); 291 timer_.Stop();
280 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(interval_ms_), 292 timer_.Start(FROM_HERE, interval_, this, &HeartbeatSender::SendStanza);
281 this, &HeartbeatSender::SendStanza);
282 } 293 }
283 } 294 }
284 } 295 }
285 296
286 void HeartbeatSender::SetSequenceId(int sequence_id) { 297 void HeartbeatSender::SetSequenceId(int sequence_id) {
287 sequence_id_ = sequence_id; 298 sequence_id_ = sequence_id;
288 // Setting the sequence ID may be a symptom of a temporary server-side 299 // Setting the sequence ID may be a symptom of a temporary server-side
289 // problem, which would affect many hosts, so don't send a new heartbeat 300 // problem, which would affect many hosts, so don't send a new heartbeat
290 // immediately, as many hosts doing so may overload the server. 301 // immediately, as many hosts doing so may overload the server.
291 // But the server will usually set the sequence ID when it receives the first 302 // But the server will usually set the sequence ID when it receives the first
292 // heartbeat from a host. In that case, we can send a new heartbeat 303 // heartbeat from a host. In that case, we can send a new heartbeat
293 // immediately, as that only happens once per host instance. 304 // immediately, as that only happens once per host instance.
294 if (!sequence_id_was_set_) { 305 if (!sequence_id_was_set_) {
295 ResendStanza(); 306 ResendStanza();
296 } else { 307 } else {
297 HOST_LOG << "The heartbeat sequence ID has been set more than once: " 308 HOST_LOG << "The heartbeat sequence ID has been set more than once: "
298 << "the new value is " << sequence_id; 309 << "the new value is " << sequence_id;
299 double delay = pow(2.0, sequence_id_recent_set_num_) * 310 base::TimeDelta delay = pow(2.0, sequence_id_recent_set_num_) *
300 (1 + base::RandDouble()) * kResendDelayMs; 311 (1 + base::RandDouble()) * kResendDelay;
301 if (delay <= interval_ms_) { 312 if (delay <= interval_) {
302 timer_resend_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay), 313 timer_resend_.Start(FROM_HERE, delay, this,
303 this, &HeartbeatSender::ResendStanza); 314 &HeartbeatSender::ResendStanza);
304 } 315 }
305 } 316 }
306 sequence_id_was_set_ = true; 317 sequence_id_was_set_ = true;
307 } 318 }
308 319
309 std::unique_ptr<XmlElement> HeartbeatSender::CreateHeartbeatMessage() { 320 std::unique_ptr<XmlElement> HeartbeatSender::CreateHeartbeatMessage() {
310 // Create heartbeat stanza. 321 // Create heartbeat stanza.
311 std::unique_ptr<XmlElement> heartbeat( 322 std::unique_ptr<XmlElement> heartbeat(
312 new XmlElement(QName(kChromotingXmlNamespace, kHeartbeatQueryTag))); 323 new XmlElement(QName(kChromotingXmlNamespace, kHeartbeatQueryTag)));
313 heartbeat->AddAttr(QName(kChromotingXmlNamespace, kHostIdAttr), host_id_); 324 heartbeat->AddAttr(QName(kChromotingXmlNamespace, kHostIdAttr), host_id_);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 363
353 std::string message = signal_strategy_->GetLocalAddress().jid() + ' ' + 364 std::string message = signal_strategy_->GetLocalAddress().jid() + ' ' +
354 base::IntToString(sequence_id_); 365 base::IntToString(sequence_id_);
355 std::string signature(host_key_pair_->SignMessage(message)); 366 std::string signature(host_key_pair_->SignMessage(message));
356 signature_tag->AddText(signature); 367 signature_tag->AddText(signature);
357 368
358 return signature_tag; 369 return signature_tag;
359 } 370 }
360 371
361 } // namespace remoting 372 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/heartbeat_sender.h ('k') | remoting/host/heartbeat_sender_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698