blob: f30c07af1136f24d617036210e8889188d503853 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/timer.h"
#include "remoting/host/host_key_pair.h"
#include "remoting/host/host_status_observer.h"
#include "remoting/jingle_glue/iq_request.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
namespace base {
class MessageLoopProxy;
} // namespace base
namespace remoting {
class IqRequest;
class HostKeyPair;
class MutableHostConfig;
// HeartbeatSender periodically sends heartbeat stanzas to the Chromoting Bot.
// Each heartbeat stanza looks as follows:
// <iq type="set" to=""
// from="" id="5" xmlns="jabber:client">
// <rem:heartbeat rem:hostid="a1ddb11e-8aef-11df-bccf-18a905b9cb5a"
// xmlns:rem="google:remoting">
// <rem:signature rem:time="1279061748">.signature.</rem:signature>
// </rem:heartbeat>
// </iq>
// The time attribute of the signature is the decimal time when the message
// was sent in second since the epoch (01/01/1970). The signature is a BASE64
// encoded SHA-1/RSA signature created with the host's private key. The message
// being signed is the full Jid concatenated with the time value, separated by
// space. For example, for the heartbeat stanza above the message that is being
// signed is " 1279061748".
// Bot sends the following result stanza in response to each heartbeat:
// <iq type="set" from=""
// to="" id="5" xmlns="jabber:client">
// <rem:heartbeat-result xmlns:rem="google:remoting">
// <rem:set-interval>300</rem:set-interval>
// </rem:heartbeat>
// </iq>
// The set-interval tag is used to specify desired heartbeat interval
// in seconds. The heartbeat-result and the set-interval tags are
// optional. Host uses default heartbeat interval if it doesn't find
// set-interval tag in the result Iq stanza it receives from the
// server.
// TODO(sergeyu): Is it enough to sign JID and nothing else?
class HeartbeatSender : public HostStatusObserver {
HeartbeatSender(base::MessageLoopProxy* main_loop,
MutableHostConfig* config);
virtual ~HeartbeatSender();
// Initializes heart-beating for |jingle_client_| with |config_|. Returns
// false if the config is invalid (e.g. private key cannot be parsed).
bool Init();
// HostStatusObserver implementation.
virtual void OnSignallingConnected(SignalStrategy* signal_strategy,
const std::string& full_jid) OVERRIDE;
virtual void OnSignallingDisconnected() OVERRIDE;
virtual void OnClientAuthenticated(
remoting::protocol::ConnectionToClient* client) OVERRIDE;
virtual void OnClientDisconnected(
remoting::protocol::ConnectionToClient* client) OVERRIDE;
virtual void OnAccessDenied() OVERRIDE;
virtual void OnShutdown() OVERRIDE;
FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, DoSendStanza);
FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, CreateHeartbeatMessage);
FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, ProcessResponse);
enum State {
void DoSendStanza();
void ProcessResponse(const buzz::XmlElement* response);
void SetInterval(int interval);
// Helper methods used by DoSendStanza() to generate heartbeat stanzas.
// Caller owns the result.
buzz::XmlElement* CreateHeartbeatMessage();
buzz::XmlElement* CreateSignature();
State state_;
scoped_refptr<base::MessageLoopProxy> message_loop_;
scoped_refptr<MutableHostConfig> config_;
std::string host_id_;
HostKeyPair key_pair_;
std::string full_jid_;
scoped_ptr<IqRequest> request_;
int interval_ms_;
base::RepeatingTimer<HeartbeatSender> timer_;
} // namespace remoting