blob: af739b0930e5be1acd21584d71d6f248db07cf7b [file] [log] [blame]
[email protected]564e40d02011-06-21 19:00:361// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]cb3b1f9312010-06-07 19:58:232// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/host/heartbeat_sender.h"
6
7#include "base/logging.h"
[email protected]60fc96002011-08-12 23:07:058#include "base/message_loop_proxy.h"
[email protected]cdf8c572010-08-04 23:04:059#include "base/string_number_conversions.h"
10#include "base/time.h"
[email protected]cb3b1f9312010-06-07 19:58:2311#include "remoting/base/constants.h"
[email protected]34f09f1a2010-06-15 23:00:2612#include "remoting/host/host_config.h"
[email protected]cb3b1f9312010-06-07 19:58:2313#include "remoting/jingle_glue/iq_request.h"
[email protected]cb3b1f9312010-06-07 19:58:2314#include "remoting/jingle_glue/jingle_thread.h"
[email protected]b6e2d6a62011-06-29 22:31:0415#include "remoting/jingle_glue/signal_strategy.h"
[email protected]cdf8c572010-08-04 23:04:0516#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
17#include "third_party/libjingle/source/talk/xmpp/constants.h"
[email protected]cb3b1f9312010-06-07 19:58:2318
[email protected]0e097f902010-12-14 03:05:4019using buzz::QName;
20using buzz::XmlElement;
21
[email protected]cb3b1f9312010-06-07 19:58:2322namespace remoting {
23
24namespace {
[email protected]cdf8c572010-08-04 23:04:0525const char kHeartbeatQueryTag[] = "heartbeat";
26const char kHostIdAttr[] = "hostid";
27const char kHeartbeatSignatureTag[] = "signature";
28const char kSignatureTimeAttr[] = "time";
[email protected]cb3b1f9312010-06-07 19:58:2329
[email protected]0e097f902010-12-14 03:05:4030const char kHeartbeatResultTag[] = "heartbeat-result";
31const char kSetIntervalTag[] = "set-interval";
32
33const int64 kDefaultHeartbeatIntervalMs = 5 * 60 * 1000; // 5 minutes.
[email protected]cb3b1f9312010-06-07 19:58:2334}
35
[email protected]60fc96002011-08-12 23:07:0536HeartbeatSender::HeartbeatSender(base::MessageLoopProxy* message_loop,
[email protected]e05eb1d2011-03-03 15:56:5737 MutableHostConfig* config)
38
[email protected]0e097f902010-12-14 03:05:4039 : state_(CREATED),
[email protected]e05eb1d2011-03-03 15:56:5740 message_loop_(message_loop),
[email protected]e05eb1d2011-03-03 15:56:5741 config_(config),
[email protected]0e097f902010-12-14 03:05:4042 interval_ms_(kDefaultHeartbeatIntervalMs) {
[email protected]e05eb1d2011-03-03 15:56:5743 DCHECK(config_);
[email protected]cb3b1f9312010-06-07 19:58:2344}
45
[email protected]cdf8c572010-08-04 23:04:0546HeartbeatSender::~HeartbeatSender() {
47 DCHECK(state_ == CREATED || state_ == INITIALIZED || state_ == STOPPED);
48}
[email protected]cb3b1f9312010-06-07 19:58:2349
[email protected]e05eb1d2011-03-03 15:56:5750bool HeartbeatSender::Init() {
[email protected]cdf8c572010-08-04 23:04:0551 DCHECK(state_ == CREATED);
[email protected]cb3b1f9312010-06-07 19:58:2352
[email protected]76207352010-06-17 23:43:0053 if (!config_->GetString(kHostIdConfigPath, &host_id_)) {
54 LOG(ERROR) << "host_id is not defined in the config.";
[email protected]cdf8c572010-08-04 23:04:0555 return false;
56 }
57
[email protected]e05eb1d2011-03-03 15:56:5758 if (!key_pair_.Load(config_)) {
[email protected]cdf8c572010-08-04 23:04:0559 return false;
60 }
61
62 state_ = INITIALIZED;
63
64 return true;
65}
66
[email protected]f6bca1f2011-05-03 20:07:4067void HeartbeatSender::OnSignallingConnected(SignalStrategy* signal_strategy,
68 const std::string& full_jid) {
[email protected]60fc96002011-08-12 23:07:0569 DCHECK(message_loop_->BelongsToCurrentThread());
[email protected]f6bca1f2011-05-03 20:07:4070 DCHECK(state_ == INITIALIZED || state_ == STOPPED);
[email protected]cdf8c572010-08-04 23:04:0571 state_ = STARTED;
[email protected]cb3b1f9312010-06-07 19:58:2372
[email protected]f6bca1f2011-05-03 20:07:4073 full_jid_ = full_jid;
74 request_.reset(signal_strategy->CreateIqRequest());
[email protected]95def6d2010-06-08 01:50:4175 request_->set_callback(NewCallback(this, &HeartbeatSender::ProcessResponse));
[email protected]cb3b1f9312010-06-07 19:58:2376
[email protected]f6bca1f2011-05-03 20:07:4077 DoSendStanza();
78 timer_.Start(base::TimeDelta::FromMilliseconds(interval_ms_), this,
79 &HeartbeatSender::DoSendStanza);
[email protected]cb3b1f9312010-06-07 19:58:2380}
81
[email protected]f6bca1f2011-05-03 20:07:4082void HeartbeatSender::OnSignallingDisconnected() {
[email protected]60fc96002011-08-12 23:07:0583 DCHECK(message_loop_->BelongsToCurrentThread());
[email protected]cdf8c572010-08-04 23:04:0584 state_ = STOPPED;
85 request_.reset(NULL);
86}
87
[email protected]273d0de7c2011-06-20 21:18:1088// Ignore any notifications other than signalling
89// connected/disconnected events.
90void HeartbeatSender::OnAccessDenied() { }
[email protected]e00804002011-08-03 00:10:3891void HeartbeatSender::OnClientAuthenticated(
92 remoting::protocol::ConnectionToClient* client) { }
93void HeartbeatSender::OnClientDisconnected(
94 remoting::protocol::ConnectionToClient* client) { }
[email protected]273d0de7c2011-06-20 21:18:1095void HeartbeatSender::OnShutdown() { }
[email protected]f6bca1f2011-05-03 20:07:4096
[email protected]cb3b1f9312010-06-07 19:58:2397void HeartbeatSender::DoSendStanza() {
[email protected]60fc96002011-08-12 23:07:0598 DCHECK(message_loop_->BelongsToCurrentThread());
[email protected]f6bca1f2011-05-03 20:07:4099 DCHECK_EQ(state_, STARTED);
[email protected]cb3b1f9312010-06-07 19:58:23100
[email protected]f6bca1f2011-05-03 20:07:40101 VLOG(1) << "Sending heartbeat stanza to " << kChromotingBotJid;
102 request_->SendIq(buzz::STR_SET, kChromotingBotJid, CreateHeartbeatMessage());
[email protected]cb3b1f9312010-06-07 19:58:23103}
104
[email protected]0e097f902010-12-14 03:05:40105void HeartbeatSender::ProcessResponse(const XmlElement* response) {
[email protected]60fc96002011-08-12 23:07:05106 DCHECK(message_loop_->BelongsToCurrentThread());
[email protected]f6bca1f2011-05-03 20:07:40107
[email protected]0e097f902010-12-14 03:05:40108 std::string type = response->Attr(buzz::QN_TYPE);
109 if (type == buzz::STR_ERROR) {
[email protected]95def6d2010-06-08 01:50:41110 LOG(ERROR) << "Received error in response to heartbeat: "
111 << response->Str();
[email protected]0e097f902010-12-14 03:05:40112 return;
113 }
114
115 // This method must only be called for error or result stanzas.
116 DCHECK_EQ(buzz::STR_RESULT, type);
117
118 const XmlElement* result_element =
119 response->FirstNamed(QName(kChromotingXmlNamespace, kHeartbeatResultTag));
120 if (result_element) {
121 const XmlElement* set_interval_element =
122 result_element->FirstNamed(QName(kChromotingXmlNamespace,
123 kSetIntervalTag));
124 if (set_interval_element) {
125 const std::string& interval_str = set_interval_element->BodyText();
126 int interval;
127 if (!base::StringToInt(interval_str, &interval) || interval <= 0) {
128 LOG(ERROR) << "Received invalid set-interval: "
129 << set_interval_element->Str();
130 } else {
[email protected]f6bca1f2011-05-03 20:07:40131 SetInterval(interval * base::Time::kMillisecondsPerSecond);
[email protected]0e097f902010-12-14 03:05:40132 }
133 }
[email protected]95def6d2010-06-08 01:50:41134 }
135}
136
[email protected]f6bca1f2011-05-03 20:07:40137void HeartbeatSender::SetInterval(int interval) {
138 if (interval != interval_ms_) {
139 interval_ms_ = interval;
140
141 // Restart the timer with the new interval.
142 if (state_ == STARTED) {
143 timer_.Stop();
144 timer_.Start(base::TimeDelta::FromMilliseconds(interval_ms_), this,
145 &HeartbeatSender::DoSendStanza);
146 }
147 }
148}
149
[email protected]0e097f902010-12-14 03:05:40150XmlElement* HeartbeatSender::CreateHeartbeatMessage() {
151 XmlElement* query = new XmlElement(
152 QName(kChromotingXmlNamespace, kHeartbeatQueryTag));
153 query->AddAttr(QName(kChromotingXmlNamespace, kHostIdAttr), host_id_);
[email protected]cdf8c572010-08-04 23:04:05154 query->AddElement(CreateSignature());
155 return query;
156}
157
[email protected]0e097f902010-12-14 03:05:40158XmlElement* HeartbeatSender::CreateSignature() {
159 XmlElement* signature_tag = new XmlElement(
160 QName(kChromotingXmlNamespace, kHeartbeatSignatureTag));
[email protected]cdf8c572010-08-04 23:04:05161
162 int64 time = static_cast<int64>(base::Time::Now().ToDoubleT());
163 std::string time_str(base::Int64ToString(time));
164 signature_tag->AddAttr(
[email protected]0e097f902010-12-14 03:05:40165 QName(kChromotingXmlNamespace, kSignatureTimeAttr), time_str);
[email protected]cdf8c572010-08-04 23:04:05166
[email protected]f6bca1f2011-05-03 20:07:40167 std::string message = full_jid_ + ' ' + time_str;
[email protected]cdf8c572010-08-04 23:04:05168 std::string signature(key_pair_.GetSignature(message));
169 signature_tag->AddText(signature);
170
171 return signature_tag;
172}
173
[email protected]cb3b1f9312010-06-07 19:58:23174} // namespace remoting