15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/heartbeat_sender.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <math.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
125e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/stringize_macros.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/base/constants.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "remoting/base/logging.h"
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/host/server_log_entry_host.h"
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "remoting/signaling/iq_sender.h"
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "remoting/signaling/server_log_entry.h"
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "remoting/signaling/signal_strategy.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/libjingle/source/talk/xmpp/constants.h"
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using buzz::QName;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using buzz::XmlElement;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHeartbeatQueryTag[] = "heartbeat";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHostIdAttr[] = "hostid";
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kHostVersionTag[] = "host-version";
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHeartbeatSignatureTag[] = "signature";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSequenceIdAttr[] = "sequence-id";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kErrorTag[] = "error";
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNotFoundTag[] = "item-not-found";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHeartbeatResultTag[] = "heartbeat-result";
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSetIntervalTag[] = "set-interval";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kExpectedSequenceIdTag[] = "expected-sequence-id";
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int64 kDefaultHeartbeatIntervalMs = 5 * 60 * 1000;  // 5 minutes.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int64 kResendDelayMs = 10 * 1000;  // 10 seconds.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int64 kResendDelayOnHostNotFoundMs = 10 * 1000; // 10 seconds.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxResendOnHostNotFoundCount = 12;  // 2 minutes (12 x 10 seconds).
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HeartbeatSender::HeartbeatSender(
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Listener* listener,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host_id,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SignalStrategy* signal_strategy,
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<RsaKeyPair> key_pair,
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_bot_jid)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : listener_(listener),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_id_(host_id),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signal_strategy_(signal_strategy),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_pair_(key_pair),
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      directory_bot_jid_(directory_bot_jid),
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      interval_ms_(kDefaultHeartbeatIntervalMs),
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sequence_id_(0),
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sequence_id_was_set_(false),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sequence_id_recent_set_num_(0),
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      heartbeat_succeeded_(false),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      failed_startup_heartbeat_count_(0) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(signal_strategy_);
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(key_pair_.get());
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal_strategy_->AddListener(this);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start heartbeats if the |signal_strategy_| is already connected.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnSignalStrategyStateChange(signal_strategy_->GetState());
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HeartbeatSender::~HeartbeatSender() {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal_strategy_->RemoveListener(this);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeartbeatSender::OnSignalStrategyStateChange(SignalStrategy::State state) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state == SignalStrategy::CONNECTED) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iq_sender_.reset(new IqSender(signal_strategy_));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendStanza();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(interval_ms_),
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, &HeartbeatSender::SendStanza);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (state == SignalStrategy::DISCONNECTED) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_.reset();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iq_sender_.reset();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_.Stop();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_resend_.Stop();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HeartbeatSender::OnSignalStrategyIncomingStanza(
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const buzz::XmlElement* stanza) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeartbeatSender::SendStanza() {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoSendStanza();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we don't send another heartbeat before the heartbeat interval
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // has expired.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_resend_.Stop();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeartbeatSender::ResendStanza() {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoSendStanza();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we don't send another heartbeat before the heartbeat interval
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // has expired.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Reset();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeartbeatSender::DoSendStanza() {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Sending heartbeat stanza to " << directory_bot_jid_;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_ = iq_sender_->SendIq(
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      buzz::STR_SET, directory_bot_jid_, CreateHeartbeatMessage(),
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&HeartbeatSender::ProcessResponse,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++sequence_id_;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeartbeatSender::ProcessResponse(IqRequest* request,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const XmlElement* response) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string type = response->Attr(buzz::QN_TYPE);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == buzz::STR_ERROR) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const XmlElement* error_element =
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        response->FirstNamed(QName(buzz::NS_CLIENT, kErrorTag));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error_element) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (error_element->FirstNamed(QName(buzz::NS_STANZA, kNotFoundTag))) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Received error: Host ID not found";
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the host was registered immediately before it sends a heartbeat,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // then server-side latency may prevent the server recognizing the
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // host ID in the heartbeat. So even if all of the first few heartbeats
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // get a "host ID not found" error, that's not a good enough reason to
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // exit.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        failed_startup_heartbeat_count_++;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!heartbeat_succeeded_ && (failed_startup_heartbeat_count_ <=
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                kMaxResendOnHostNotFoundCount)) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          timer_resend_.Start(FROM_HERE,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              base::TimeDelta::FromMilliseconds(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  kResendDelayOnHostNotFoundMs),
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              this,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &HeartbeatSender::ResendStanza);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        listener_->OnUnknownHostIdError();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Received error in response to heartbeat: "
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << response->Str();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Notify listener of the first successful heartbeat.
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!heartbeat_succeeded_) {
1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    listener_->OnHeartbeatSuccessful();
1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  heartbeat_succeeded_ = true;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method must only be called for error or result stanzas.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(std::string(buzz::STR_RESULT), type);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const XmlElement* result_element =
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response->FirstNamed(QName(kChromotingXmlNamespace, kHeartbeatResultTag));
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result_element) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const XmlElement* set_interval_element =
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result_element->FirstNamed(QName(kChromotingXmlNamespace,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         kSetIntervalTag));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (set_interval_element) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& interval_str = set_interval_element->BodyText();
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int interval;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!base::StringToInt(interval_str, &interval) || interval <= 0) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Received invalid set-interval: "
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << set_interval_element->Str();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetInterval(interval * base::Time::kMillisecondsPerSecond);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool did_set_sequence_id = false;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const XmlElement* expected_sequence_id_element =
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result_element->FirstNamed(QName(kChromotingXmlNamespace,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         kExpectedSequenceIdTag));
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (expected_sequence_id_element) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The sequence ID sent in the previous heartbeat was not what the server
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // expected, so send another heartbeat with the expected sequence ID.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& expected_sequence_id_str =
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          expected_sequence_id_element->BodyText();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int expected_sequence_id;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!base::StringToInt(expected_sequence_id_str, &expected_sequence_id)) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Received invalid " << kExpectedSequenceIdTag << ": " <<
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            expected_sequence_id_element->Str();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetSequenceId(expected_sequence_id);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sequence_id_recent_set_num_++;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        did_set_sequence_id = true;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!did_set_sequence_id) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sequence_id_recent_set_num_ = 0;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeartbeatSender::SetInterval(int interval) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (interval != interval_ms_) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    interval_ms_ = interval;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Restart the timer with the new interval.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (timer_.IsRunning()) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Stop();
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(interval_ms_),
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   this, &HeartbeatSender::SendStanza);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeartbeatSender::SetSequenceId(int sequence_id) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sequence_id_ = sequence_id;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Setting the sequence ID may be a symptom of a temporary server-side
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // problem, which would affect many hosts, so don't send a new heartbeat
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // immediately, as many hosts doing so may overload the server.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // But the server will usually set the sequence ID when it receives the first
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // heartbeat from a host. In that case, we can send a new heartbeat
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // immediately, as that only happens once per host instance.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!sequence_id_was_set_) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResendStanza();
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    HOST_LOG << "The heartbeat sequence ID has been set more than once: "
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << "the new value is " << sequence_id;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double delay = pow(2.0, sequence_id_recent_set_num_) *
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (1 + base::RandDouble()) * kResendDelayMs;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delay <= interval_ms_) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_resend_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay),
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          this, &HeartbeatSender::ResendStanza);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sequence_id_was_set_ = true;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<XmlElement> HeartbeatSender::CreateHeartbeatMessage() {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create heartbeat stanza.
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<XmlElement> heartbeat(new XmlElement(
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, kHeartbeatQueryTag)));
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heartbeat->AddAttr(QName(kChromotingXmlNamespace, kHostIdAttr), host_id_);
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heartbeat->AddAttr(QName(kChromotingXmlNamespace, kSequenceIdAttr),
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::IntToString(sequence_id_));
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heartbeat->AddElement(CreateSignature().release());
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Append host version.
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<XmlElement> version_tag(new XmlElement(
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      QName(kChromotingXmlNamespace, kHostVersionTag)));
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  version_tag->AddText(STRINGIZE(VERSION));
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heartbeat->AddElement(version_tag.release());
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Append log message (which isn't signed).
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<XmlElement> log(ServerLogEntry::MakeStanza());
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<ServerLogEntry> log_entry(MakeLogEntryForHeartbeat());
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AddHostFieldsToLogEntry(log_entry.get());
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log->AddElement(log_entry->ToStanza().release());
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heartbeat->AddElement(log.release());
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return heartbeat.Pass();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<XmlElement> HeartbeatSender::CreateSignature() {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<XmlElement> signature_tag(new XmlElement(
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, kHeartbeatSignatureTag)));
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string message = signal_strategy_->GetLocalJid() + ' ' +
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::IntToString(sequence_id_);
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string signature(key_pair_->SignMessage(message));
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signature_tag->AddText(signature);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return signature_tag.Pass();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
279