Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / host / heartbeat_sender.h
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
3 // found in the LICENSE file.
4
5 #ifndef REMOTING_HOST_HEARTBEAT_SENDER_H_
6 #define REMOTING_HOST_HEARTBEAT_SENDER_H_
7
8 #include <string>
9
10 #include "base/compiler_specific.h"
11 #include "base/gtest_prod_util.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/timer/timer.h"
15 #include "remoting/base/rsa_key_pair.h"
16 #include "remoting/signaling/signal_strategy.h"
17
18 namespace base {
19 class MessageLoopProxy;
20 }  // namespace base
21
22 namespace buzz {
23 class XmlElement;
24 }  // namespace buzz
25
26 namespace remoting {
27
28 class RsaKeyPair;
29 class IqRequest;
30 class IqSender;
31
32 // HeartbeatSender periodically sends heartbeat stanzas to the Chromoting Bot.
33 // Each heartbeat stanza looks as follows:
34 //
35 // <iq type="set" to="remoting@bot.talk.google.com"
36 //     from="user@gmail.com/chromoting123123" id="5" xmlns="jabber:client">
37 //   <rem:heartbeat rem:hostid="a1ddb11e-8aef-11df-bccf-18a905b9cb5a"
38 //                  rem:sequence-id="456"
39 //                  xmlns:rem="google:remoting">
40 //     <rem:signature>.signature.</rem:signature>
41 //   </rem:heartbeat>
42 // </iq>
43 //
44 // The sequence-id attribute of the heartbeat is a zero-based incrementally
45 // increasing integer unique to each heartbeat from a single host.
46 // The Bot checks the value, and if it is incorrect, includes the
47 // correct value in the result stanza. The host should then send another
48 // heartbeat, with the correct sequence-id, and increment the sequence-id in
49 // susbequent heartbeats.
50 // The signature is a base-64 encoded SHA-1 hash, signed with the host's
51 // private RSA key. The message being signed is the full Jid concatenated with
52 // the sequence-id, separated by one space. For example, for the heartbeat
53 // stanza above, the message that is signed is
54 // "user@gmail.com/chromoting123123 456".
55 //
56 // The Bot sends the following result stanza in response to each successful
57 // heartbeat:
58 //
59 //  <iq type="set" from="remoting@bot.talk.google.com"
60 //      to="user@gmail.com/chromoting123123" id="5" xmlns="jabber:client">
61 //    <rem:heartbeat-result xmlns:rem="google:remoting">
62 //      <rem:set-interval>300</rem:set-interval>
63 //    </rem:heartbeat-result>
64 //  </iq>
65 //
66 // The set-interval tag is used to specify desired heartbeat interval
67 // in seconds. The heartbeat-result and the set-interval tags are
68 // optional. Host uses default heartbeat interval if it doesn't find
69 // set-interval tag in the result Iq stanza it receives from the
70 // server.
71 // If the heartbeat's sequence-id was incorrect, the Bot sends a result
72 // stanza of this form:
73 //
74 //  <iq type="set" from="remoting@bot.talk.google.com"
75 //      to="user@gmail.com/chromoting123123" id="5" xmlns="jabber:client">
76 //    <rem:heartbeat-result xmlns:rem="google:remoting">
77 //      <rem:expected-sequence-id>654</rem:expected-sequence-id>
78 //    </rem:heartbeat-result>
79 //  </iq>
80 class HeartbeatSender : public SignalStrategy::Listener {
81  public:
82   class Listener {
83    public:
84     virtual ~Listener() { }
85
86     // Invoked after the first successful heartbeat.
87     virtual void OnHeartbeatSuccessful() = 0;
88
89     // Invoked when the host ID is permanently not recognized by the server.
90     virtual void OnUnknownHostIdError() = 0;
91   };
92
93   // |signal_strategy| and |delegate| must outlive this
94   // object. Heartbeats will start when the supplied SignalStrategy
95   // enters the CONNECTED state.
96   HeartbeatSender(Listener* listener,
97                   const std::string& host_id,
98                   SignalStrategy* signal_strategy,
99                   scoped_refptr<RsaKeyPair> key_pair,
100                   const std::string& directory_bot_jid);
101   ~HeartbeatSender() override;
102
103   // SignalStrategy::Listener interface.
104   void OnSignalStrategyStateChange(SignalStrategy::State state) override;
105   bool OnSignalStrategyIncomingStanza(const buzz::XmlElement* stanza) override;
106
107  private:
108   FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, DoSendStanza);
109   FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest,
110                            DoSendStanzaWithExpectedSequenceId);
111   FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, CreateHeartbeatMessage);
112   FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, ProcessResponseSetInterval);
113   FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest,
114                            ProcessResponseExpectedSequenceId);
115
116   void SendStanza();
117   void ResendStanza();
118   void DoSendStanza();
119   void ProcessResponse(IqRequest* request, const buzz::XmlElement* response);
120   void SetInterval(int interval);
121   void SetSequenceId(int sequence_id);
122
123   // Helper methods used by DoSendStanza() to generate heartbeat stanzas.
124   scoped_ptr<buzz::XmlElement> CreateHeartbeatMessage();
125   scoped_ptr<buzz::XmlElement> CreateSignature();
126
127   Listener* listener_;
128   std::string host_id_;
129   SignalStrategy* signal_strategy_;
130   scoped_refptr<RsaKeyPair> key_pair_;
131   std::string directory_bot_jid_;
132   scoped_ptr<IqSender> iq_sender_;
133   scoped_ptr<IqRequest> request_;
134   int interval_ms_;
135   base::RepeatingTimer<HeartbeatSender> timer_;
136   base::OneShotTimer<HeartbeatSender> timer_resend_;
137   int sequence_id_;
138   bool sequence_id_was_set_;
139   int sequence_id_recent_set_num_;
140   bool heartbeat_succeeded_;
141   int failed_startup_heartbeat_count_;
142
143   DISALLOW_COPY_AND_ASSIGN(HeartbeatSender);
144 };
145
146 }  // namespace remoting
147
148 #endif  // REMOTING_HOST_HEARTBEAT_SENDER_H_