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)#ifndef REMOTING_HOST_HEARTBEAT_SENDER_H_ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define REMOTING_HOST_HEARTBEAT_SENDER_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/gtest_prod_util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/base/rsa_key_pair.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/jingle_glue/signal_strategy.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MessageLoopProxy; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace buzz { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class XmlElement; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace buzz 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class RsaKeyPair; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IqRequest; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IqSender; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HeartbeatSender periodically sends heartbeat stanzas to the Chromoting Bot. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each heartbeat stanza looks as follows: 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <iq type="set" to="remoting@bot.talk.google.com" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from="user@gmail.com/chromoting123123" id="5" xmlns="jabber:client"> 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <rem:heartbeat rem:hostid="a1ddb11e-8aef-11df-bccf-18a905b9cb5a" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// rem:sequence-id="456" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// xmlns:rem="google:remoting"> 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <rem:signature>.signature.</rem:signature> 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// </rem:heartbeat> 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// </iq> 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The sequence-id attribute of the heartbeat is a zero-based incrementally 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// increasing integer unique to each heartbeat from a single host. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The Bot checks the value, and if it is incorrect, includes the 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// correct value in the result stanza. The host should then send another 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// heartbeat, with the correct sequence-id, and increment the sequence-id in 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// susbequent heartbeats. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The signature is a base-64 encoded SHA-1 hash, signed with the host's 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// private RSA key. The message being signed is the full Jid concatenated with 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the sequence-id, separated by one space. For example, for the heartbeat 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// stanza above, the message that is signed is 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "user@gmail.com/chromoting123123 456". 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The Bot sends the following result stanza in response to each successful 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// heartbeat: 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <iq type="set" from="remoting@bot.talk.google.com" 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to="user@gmail.com/chromoting123123" id="5" xmlns="jabber:client"> 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <rem:heartbeat-result xmlns:rem="google:remoting"> 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <rem:set-interval>300</rem:set-interval> 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// </rem:heartbeat-result> 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// </iq> 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The set-interval tag is used to specify desired heartbeat interval 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in seconds. The heartbeat-result and the set-interval tags are 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// optional. Host uses default heartbeat interval if it doesn't find 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// set-interval tag in the result Iq stanza it receives from the 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// server. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the heartbeat's sequence-id was incorrect, the Bot sends a result 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// stanza of this form: 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <iq type="set" from="remoting@bot.talk.google.com" 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to="user@gmail.com/chromoting123123" id="5" xmlns="jabber:client"> 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <rem:heartbeat-result xmlns:rem="google:remoting"> 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <rem:expected-sequence-id>654</rem:expected-sequence-id> 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// </rem:heartbeat-result> 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// </iq> 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HeartbeatSender : public SignalStrategy::Listener { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class Listener { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~Listener() { } 857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Invoked after the first successful heartbeat. 877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) virtual void OnHeartbeatSuccessful() = 0; 887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Invoked when the host ID is permanently not recognized by the server. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnUnknownHostIdError() = 0; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |signal_strategy| and |delegate| must outlive this 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // object. Heartbeats will start when the supplied SignalStrategy 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // enters the CONNECTED state. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeartbeatSender(Listener* listener, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& host_id, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SignalStrategy* signal_strategy, 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<RsaKeyPair> key_pair, 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& directory_bot_jid); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~HeartbeatSender(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SignalStrategy::Listener interface. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnSignalStrategyStateChange( 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SignalStrategy::State state) OVERRIDE; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool OnSignalStrategyIncomingStanza( 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const buzz::XmlElement* stanza) OVERRIDE; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, DoSendStanza); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoSendStanzaWithExpectedSequenceId); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, CreateHeartbeatMessage); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, ProcessResponseSetInterval); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessResponseExpectedSequenceId); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SendStanza(); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ResendStanza(); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DoSendStanza(); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ProcessResponse(IqRequest* request, const buzz::XmlElement* response); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetInterval(int interval); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetSequenceId(int sequence_id); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper methods used by DoSendStanza() to generate heartbeat stanzas. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<buzz::XmlElement> CreateHeartbeatMessage(); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<buzz::XmlElement> CreateSignature(); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Listener* listener_; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string host_id_; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SignalStrategy* signal_strategy_; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<RsaKeyPair> key_pair_; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string directory_bot_jid_; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<IqSender> iq_sender_; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<IqRequest> request_; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int interval_ms_; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::RepeatingTimer<HeartbeatSender> timer_; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::OneShotTimer<HeartbeatSender> timer_resend_; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int sequence_id_; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool sequence_id_was_set_; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int sequence_id_recent_set_num_; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool heartbeat_succeeded_; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int failed_startup_heartbeat_count_; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(HeartbeatSender); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace remoting 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // REMOTING_HOST_HEARTBEAT_SENDER_H_ 151