| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/heartbeat_sender.h" | 5 #include "remoting/host/heartbeat_sender.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
| 10 #include "base/time.h" | 10 #include "base/time.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 const char kHeartbeatSignatureTag[] = "signature"; | 27 const char kHeartbeatSignatureTag[] = "signature"; |
| 28 const char kSignatureTimeAttr[] = "time"; | 28 const char kSignatureTimeAttr[] = "time"; |
| 29 | 29 |
| 30 const char kHeartbeatResultTag[] = "heartbeat-result"; | 30 const char kHeartbeatResultTag[] = "heartbeat-result"; |
| 31 const char kSetIntervalTag[] = "set-interval"; | 31 const char kSetIntervalTag[] = "set-interval"; |
| 32 | 32 |
| 33 const int64 kDefaultHeartbeatIntervalMs = 5 * 60 * 1000; // 5 minutes. | 33 const int64 kDefaultHeartbeatIntervalMs = 5 * 60 * 1000; // 5 minutes. |
| 34 } | 34 } |
| 35 | 35 |
| 36 HeartbeatSender::HeartbeatSender(MessageLoop* message_loop, | 36 HeartbeatSender::HeartbeatSender(MessageLoop* message_loop, |
| 37 JingleClient* jingle_client, | |
| 38 MutableHostConfig* config) | 37 MutableHostConfig* config) |
| 39 | 38 |
| 40 : state_(CREATED), | 39 : state_(CREATED), |
| 41 message_loop_(message_loop), | 40 message_loop_(message_loop), |
| 42 jingle_client_(jingle_client), | |
| 43 config_(config), | 41 config_(config), |
| 44 interval_ms_(kDefaultHeartbeatIntervalMs) { | 42 interval_ms_(kDefaultHeartbeatIntervalMs) { |
| 45 DCHECK(jingle_client_); | |
| 46 DCHECK(config_); | 43 DCHECK(config_); |
| 47 } | 44 } |
| 48 | 45 |
| 49 HeartbeatSender::~HeartbeatSender() { | 46 HeartbeatSender::~HeartbeatSender() { |
| 50 DCHECK(state_ == CREATED || state_ == INITIALIZED || state_ == STOPPED); | 47 DCHECK(state_ == CREATED || state_ == INITIALIZED || state_ == STOPPED); |
| 51 } | 48 } |
| 52 | 49 |
| 53 bool HeartbeatSender::Init() { | 50 bool HeartbeatSender::Init() { |
| 54 DCHECK(state_ == CREATED); | 51 DCHECK(state_ == CREATED); |
| 55 | 52 |
| 56 if (!config_->GetString(kHostIdConfigPath, &host_id_)) { | 53 if (!config_->GetString(kHostIdConfigPath, &host_id_)) { |
| 57 LOG(ERROR) << "host_id is not defined in the config."; | 54 LOG(ERROR) << "host_id is not defined in the config."; |
| 58 return false; | 55 return false; |
| 59 } | 56 } |
| 60 | 57 |
| 61 if (!key_pair_.Load(config_)) { | 58 if (!key_pair_.Load(config_)) { |
| 62 return false; | 59 return false; |
| 63 } | 60 } |
| 64 | 61 |
| 65 state_ = INITIALIZED; | 62 state_ = INITIALIZED; |
| 66 | 63 |
| 67 return true; | 64 return true; |
| 68 } | 65 } |
| 69 | 66 |
| 70 void HeartbeatSender::Start() { | 67 void HeartbeatSender::OnSignallingConnected(SignalStrategy* signal_strategy, |
| 71 if (MessageLoop::current() != message_loop_) { | 68 const std::string& full_jid) { |
| 72 message_loop_->PostTask( | 69 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 73 FROM_HERE, NewRunnableMethod(this, &HeartbeatSender::Start)); | 70 DCHECK(state_ == INITIALIZED || state_ == STOPPED); |
| 74 return; | |
| 75 } | |
| 76 | |
| 77 DCHECK_EQ(INITIALIZED, state_); | |
| 78 state_ = STARTED; | 71 state_ = STARTED; |
| 79 | 72 |
| 80 request_.reset(jingle_client_->CreateIqRequest()); | 73 full_jid_ = full_jid; |
| 74 request_.reset(signal_strategy->CreateIqRequest()); |
| 81 request_->set_callback(NewCallback(this, &HeartbeatSender::ProcessResponse)); | 75 request_->set_callback(NewCallback(this, &HeartbeatSender::ProcessResponse)); |
| 82 | 76 |
| 83 message_loop_->PostTask( | 77 DoSendStanza(); |
| 84 FROM_HERE, NewRunnableMethod(this, &HeartbeatSender::DoSendStanza)); | 78 timer_.Start(base::TimeDelta::FromMilliseconds(interval_ms_), this, |
| 79 &HeartbeatSender::DoSendStanza); |
| 85 } | 80 } |
| 86 | 81 |
| 87 void HeartbeatSender::Stop() { | 82 void HeartbeatSender::OnSignallingDisconnected() { |
| 88 if (MessageLoop::current() != message_loop_) { | 83 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 89 message_loop_->PostTask( | 84 DCHECK_EQ(state_, STARTED); |
| 90 FROM_HERE, NewRunnableMethod(this, &HeartbeatSender::Stop)); | |
| 91 return; | |
| 92 } | |
| 93 | |
| 94 // We may call Stop() even if we have not started. | |
| 95 if (state_ != STARTED) | |
| 96 return; | |
| 97 state_ = STOPPED; | 85 state_ = STOPPED; |
| 98 request_.reset(NULL); | 86 request_.reset(NULL); |
| 99 } | 87 } |
| 100 | 88 |
| 89 void HeartbeatSender::OnShutdown() { |
| 90 } |
| 91 |
| 101 void HeartbeatSender::DoSendStanza() { | 92 void HeartbeatSender::DoSendStanza() { |
| 102 if (state_ == STARTED) { | 93 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 103 // |jingle_client_| may be already destroyed if |state_| is set to | 94 DCHECK_EQ(state_, STARTED); |
| 104 // |STOPPED|, so don't touch it here unless we are in |STARTED| state. | |
| 105 DCHECK(MessageLoop::current() == message_loop_); | |
| 106 | 95 |
| 107 VLOG(1) << "Sending heartbeat stanza to " << kChromotingBotJid; | 96 VLOG(1) << "Sending heartbeat stanza to " << kChromotingBotJid; |
| 108 | 97 request_->SendIq(buzz::STR_SET, kChromotingBotJid, CreateHeartbeatMessage()); |
| 109 request_->SendIq(buzz::STR_SET, kChromotingBotJid, | |
| 110 CreateHeartbeatMessage()); | |
| 111 | |
| 112 // Schedule next heartbeat. | |
| 113 message_loop_->PostDelayedTask( | |
| 114 FROM_HERE, NewRunnableMethod(this, &HeartbeatSender::DoSendStanza), | |
| 115 interval_ms_); | |
| 116 } | |
| 117 } | 98 } |
| 118 | 99 |
| 119 void HeartbeatSender::ProcessResponse(const XmlElement* response) { | 100 void HeartbeatSender::ProcessResponse(const XmlElement* response) { |
| 101 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 102 |
| 120 std::string type = response->Attr(buzz::QN_TYPE); | 103 std::string type = response->Attr(buzz::QN_TYPE); |
| 121 if (type == buzz::STR_ERROR) { | 104 if (type == buzz::STR_ERROR) { |
| 122 LOG(ERROR) << "Received error in response to heartbeat: " | 105 LOG(ERROR) << "Received error in response to heartbeat: " |
| 123 << response->Str(); | 106 << response->Str(); |
| 124 return; | 107 return; |
| 125 } | 108 } |
| 126 | 109 |
| 127 // This method must only be called for error or result stanzas. | 110 // This method must only be called for error or result stanzas. |
| 128 DCHECK_EQ(buzz::STR_RESULT, type); | 111 DCHECK_EQ(buzz::STR_RESULT, type); |
| 129 | 112 |
| 130 const XmlElement* result_element = | 113 const XmlElement* result_element = |
| 131 response->FirstNamed(QName(kChromotingXmlNamespace, kHeartbeatResultTag)); | 114 response->FirstNamed(QName(kChromotingXmlNamespace, kHeartbeatResultTag)); |
| 132 if (result_element) { | 115 if (result_element) { |
| 133 const XmlElement* set_interval_element = | 116 const XmlElement* set_interval_element = |
| 134 result_element->FirstNamed(QName(kChromotingXmlNamespace, | 117 result_element->FirstNamed(QName(kChromotingXmlNamespace, |
| 135 kSetIntervalTag)); | 118 kSetIntervalTag)); |
| 136 if (set_interval_element) { | 119 if (set_interval_element) { |
| 137 const std::string& interval_str = set_interval_element->BodyText(); | 120 const std::string& interval_str = set_interval_element->BodyText(); |
| 138 int interval; | 121 int interval; |
| 139 if (!base::StringToInt(interval_str, &interval) || interval <= 0) { | 122 if (!base::StringToInt(interval_str, &interval) || interval <= 0) { |
| 140 LOG(ERROR) << "Received invalid set-interval: " | 123 LOG(ERROR) << "Received invalid set-interval: " |
| 141 << set_interval_element->Str(); | 124 << set_interval_element->Str(); |
| 142 } else { | 125 } else { |
| 143 interval_ms_ = interval * base::Time::kMillisecondsPerSecond; | 126 SetInterval(interval * base::Time::kMillisecondsPerSecond); |
| 144 } | 127 } |
| 145 } | 128 } |
| 146 } | 129 } |
| 147 } | 130 } |
| 148 | 131 |
| 132 void HeartbeatSender::SetInterval(int interval) { |
| 133 if (interval != interval_ms_) { |
| 134 interval_ms_ = interval; |
| 135 |
| 136 // Restart the timer with the new interval. |
| 137 if (state_ == STARTED) { |
| 138 timer_.Stop(); |
| 139 timer_.Start(base::TimeDelta::FromMilliseconds(interval_ms_), this, |
| 140 &HeartbeatSender::DoSendStanza); |
| 141 } |
| 142 } |
| 143 } |
| 144 |
| 149 XmlElement* HeartbeatSender::CreateHeartbeatMessage() { | 145 XmlElement* HeartbeatSender::CreateHeartbeatMessage() { |
| 150 XmlElement* query = new XmlElement( | 146 XmlElement* query = new XmlElement( |
| 151 QName(kChromotingXmlNamespace, kHeartbeatQueryTag)); | 147 QName(kChromotingXmlNamespace, kHeartbeatQueryTag)); |
| 152 query->AddAttr(QName(kChromotingXmlNamespace, kHostIdAttr), host_id_); | 148 query->AddAttr(QName(kChromotingXmlNamespace, kHostIdAttr), host_id_); |
| 153 query->AddElement(CreateSignature()); | 149 query->AddElement(CreateSignature()); |
| 154 return query; | 150 return query; |
| 155 } | 151 } |
| 156 | 152 |
| 157 XmlElement* HeartbeatSender::CreateSignature() { | 153 XmlElement* HeartbeatSender::CreateSignature() { |
| 158 XmlElement* signature_tag = new XmlElement( | 154 XmlElement* signature_tag = new XmlElement( |
| 159 QName(kChromotingXmlNamespace, kHeartbeatSignatureTag)); | 155 QName(kChromotingXmlNamespace, kHeartbeatSignatureTag)); |
| 160 | 156 |
| 161 int64 time = static_cast<int64>(base::Time::Now().ToDoubleT()); | 157 int64 time = static_cast<int64>(base::Time::Now().ToDoubleT()); |
| 162 std::string time_str(base::Int64ToString(time)); | 158 std::string time_str(base::Int64ToString(time)); |
| 163 signature_tag->AddAttr( | 159 signature_tag->AddAttr( |
| 164 QName(kChromotingXmlNamespace, kSignatureTimeAttr), time_str); | 160 QName(kChromotingXmlNamespace, kSignatureTimeAttr), time_str); |
| 165 | 161 |
| 166 std::string message = jingle_client_->GetFullJid() + ' ' + time_str; | 162 std::string message = full_jid_ + ' ' + time_str; |
| 167 std::string signature(key_pair_.GetSignature(message)); | 163 std::string signature(key_pair_.GetSignature(message)); |
| 168 signature_tag->AddText(signature); | 164 signature_tag->AddText(signature); |
| 169 | 165 |
| 170 return signature_tag; | 166 return signature_tag; |
| 171 } | 167 } |
| 172 | 168 |
| 173 } // namespace remoting | 169 } // namespace remoting |
| OLD | NEW |