summaryrefslogtreecommitdiffstats
path: root/remoting/host/heartbeat_sender.cc
diff options
context:
space:
mode:
authorsimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-08 01:43:26 +0000
committersimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-08 01:43:26 +0000
commitda32a4602e5cd13d21e75c14380a88e78f4db5e4 (patch)
treea4448d7ffe3536ab2ca19c4785f84a8fe5c6cb90 /remoting/host/heartbeat_sender.cc
parentf98e24d6f5ec14ec771d8564288b37618ed70c3b (diff)
downloadchromium_src-da32a4602e5cd13d21e75c14380a88e78f4db5e4.zip
chromium_src-da32a4602e5cd13d21e75c14380a88e78f4db5e4.tar.gz
chromium_src-da32a4602e5cd13d21e75c14380a88e78f4db5e4.tar.bz2
The chromoting host uses heartbeat sequence IDs.
BUG=112112 TEST=Start a host, stop it, start it again, wait 10 minutes, and check the host is online. Review URL: http://codereview.chromium.org/9309005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@120898 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/host/heartbeat_sender.cc')
-rw-r--r--remoting/host/heartbeat_sender.cc90
1 files changed, 79 insertions, 11 deletions
diff --git a/remoting/host/heartbeat_sender.cc b/remoting/host/heartbeat_sender.cc
index d0eaba5..df9fa8c 100644
--- a/remoting/host/heartbeat_sender.cc
+++ b/remoting/host/heartbeat_sender.cc
@@ -4,9 +4,12 @@
#include "remoting/host/heartbeat_sender.h"
+#include <math.h>
+
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
+#include "base/rand_util.h"
#include "base/string_number_conversions.h"
#include "base/time.h"
#include "remoting/base/constants.h"
@@ -26,15 +29,17 @@ namespace {
const char kHeartbeatQueryTag[] = "heartbeat";
const char kHostIdAttr[] = "hostid";
const char kHeartbeatSignatureTag[] = "signature";
-const char kSignatureTimeAttr[] = "time";
+const char kSequenceIdAttr[] = "sequence-id";
const char kErrorTag[] = "error";
const char kNotFoundTag[] = "item-not-found";
const char kHeartbeatResultTag[] = "heartbeat-result";
const char kSetIntervalTag[] = "set-interval";
+const char kExpectedSequenceIdTag[] = "expected-sequence-id";
const int64 kDefaultHeartbeatIntervalMs = 5 * 60 * 1000; // 5 minutes.
+const int64 kResendDelayMs = 10 * 1000; // 10 seconds.
} // namespace
@@ -45,7 +50,10 @@ HeartbeatSender::HeartbeatSender(
: host_id_(host_id),
signal_strategy_(signal_strategy),
key_pair_(key_pair),
- interval_ms_(kDefaultHeartbeatIntervalMs) {
+ interval_ms_(kDefaultHeartbeatIntervalMs),
+ sequence_id_(0),
+ sequence_id_was_set_(false),
+ sequence_id_recent_set_num_(0) {
DCHECK(signal_strategy_);
DCHECK(key_pair_);
@@ -62,22 +70,38 @@ HeartbeatSender::~HeartbeatSender() {
void HeartbeatSender::OnSignalStrategyStateChange(SignalStrategy::State state) {
if (state == SignalStrategy::CONNECTED) {
iq_sender_.reset(new IqSender(signal_strategy_));
- DoSendStanza();
+ SendStanza();
timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(interval_ms_),
- this, &HeartbeatSender::DoSendStanza);
+ this, &HeartbeatSender::SendStanza);
} else if (state == SignalStrategy::DISCONNECTED) {
request_.reset();
iq_sender_.reset();
timer_.Stop();
+ timer_resend_.Stop();
}
}
+void HeartbeatSender::SendStanza() {
+ DoSendStanza();
+ // Make sure we don't send another heartbeat before the heartbeat interval
+ // has expired.
+ timer_resend_.Stop();
+}
+
+void HeartbeatSender::ResendStanza() {
+ DoSendStanza();
+ // Make sure we don't send another heartbeat before the heartbeat interval
+ // has expired.
+ timer_.Reset();
+}
+
void HeartbeatSender::DoSendStanza() {
VLOG(1) << "Sending heartbeat stanza to " << kChromotingBotJid;
request_.reset(iq_sender_->SendIq(
buzz::STR_SET, kChromotingBotJid, CreateHeartbeatMessage(),
base::Bind(&HeartbeatSender::ProcessResponse,
base::Unretained(this))));
+ ++sequence_id_;
}
void HeartbeatSender::ProcessResponse(const XmlElement* response) {
@@ -119,6 +143,29 @@ void HeartbeatSender::ProcessResponse(const XmlElement* response) {
SetInterval(interval * base::Time::kMillisecondsPerSecond);
}
}
+
+ bool did_set_sequence_id = false;
+ const XmlElement* expected_sequence_id_element =
+ result_element->FirstNamed(QName(kChromotingXmlNamespace,
+ kExpectedSequenceIdTag));
+ if (expected_sequence_id_element) {
+ // The sequence ID sent in the previous heartbeat was not what the server
+ // expected, so send another heartbeat with the expected sequence ID.
+ const std::string& expected_sequence_id_str =
+ expected_sequence_id_element->BodyText();
+ int expected_sequence_id;
+ if (!base::StringToInt(expected_sequence_id_str, &expected_sequence_id)) {
+ LOG(ERROR) << "Received invalid " << kExpectedSequenceIdTag << ": " <<
+ expected_sequence_id_element->Str();
+ } else {
+ SetSequenceId(expected_sequence_id);
+ sequence_id_recent_set_num_++;
+ did_set_sequence_id = true;
+ }
+ }
+ if (!did_set_sequence_id) {
+ sequence_id_recent_set_num_ = 0;
+ }
}
}
@@ -130,15 +177,40 @@ void HeartbeatSender::SetInterval(int interval) {
if (timer_.IsRunning()) {
timer_.Stop();
timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(interval_ms_),
- this, &HeartbeatSender::DoSendStanza);
+ this, &HeartbeatSender::SendStanza);
+ }
+ }
+}
+
+void HeartbeatSender::SetSequenceId(int sequence_id) {
+ sequence_id_ = sequence_id;
+ // Setting the sequence ID may be a symptom of a temporary server-side
+ // problem, which would affect many hosts, so don't send a new heartbeat
+ // immediately, as many hosts doing so may overload the server.
+ // But the server will usually set the sequence ID when it receives the first
+ // heartbeat from a host. In that case, we can send a new heartbeat
+ // immediately, as that only happens once per host instance.
+ if (!sequence_id_was_set_) {
+ ResendStanza();
+ } else {
+ LOG(INFO) << "The heartbeat sequence ID has been set more than once: "
+ << "the new value is " << sequence_id;
+ double delay = pow(2.0, sequence_id_recent_set_num_) *
+ (1 + base::RandDouble()) * kResendDelayMs;
+ if (delay <= interval_ms_) {
+ timer_resend_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay),
+ this, &HeartbeatSender::ResendStanza);
}
}
+ sequence_id_was_set_ = true;
}
XmlElement* HeartbeatSender::CreateHeartbeatMessage() {
XmlElement* query = new XmlElement(
QName(kChromotingXmlNamespace, kHeartbeatQueryTag));
query->AddAttr(QName(kChromotingXmlNamespace, kHostIdAttr), host_id_);
+ query->AddAttr(QName(kChromotingXmlNamespace, kSequenceIdAttr),
+ base::IntToString(sequence_id_));
query->AddElement(CreateSignature());
return query;
}
@@ -147,12 +219,8 @@ XmlElement* HeartbeatSender::CreateSignature() {
XmlElement* signature_tag = new XmlElement(
QName(kChromotingXmlNamespace, kHeartbeatSignatureTag));
- int64 time = static_cast<int64>(base::Time::Now().ToDoubleT());
- std::string time_str(base::Int64ToString(time));
- signature_tag->AddAttr(
- QName(kChromotingXmlNamespace, kSignatureTimeAttr), time_str);
-
- std::string message = signal_strategy_->GetLocalJid() + ' ' + time_str;
+ std::string message = signal_strategy_->GetLocalJid() + ' ' +
+ base::IntToString(sequence_id_);
std::string signature(key_pair_->GetSignature(message));
signature_tag->AddText(signature);