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