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)#include "remoting/host/register_support_host_request.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
99ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/base/constants.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/host_config.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "remoting/signaling/iq_sender.h"
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "remoting/signaling/signal_strategy.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/libjingle/source/talk/xmpp/constants.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using buzz::QName;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using buzz::XmlElement;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Strings used in the request message we send to the bot.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRegisterQueryTag[] = "register-support-host";
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPublicKeyTag[] = "public-key";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSignatureTag[] = "signature";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSignatureTimeAttr[] = "time";
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Strings used to parse responses received from the bot.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRegisterQueryResultTag[] = "register-support-host-result";
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSupportIdTag[] = "support-id";
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSupportIdLifetimeTag[] = "support-id-lifetime";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RegisterSupportHostRequest::RegisterSupportHostRequest(
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SignalStrategy* signal_strategy,
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<RsaKeyPair> key_pair,
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_bot_jid,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const RegisterCallback& callback)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : signal_strategy_(signal_strategy),
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_pair_(key_pair),
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      directory_bot_jid_(directory_bot_jid),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_(callback) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(signal_strategy_);
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(key_pair_.get());
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal_strategy_->AddListener(this);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iq_sender_.reset(new IqSender(signal_strategy_));
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RegisterSupportHostRequest::~RegisterSupportHostRequest() {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (signal_strategy_)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signal_strategy_->RemoveListener(this);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RegisterSupportHostRequest::OnSignalStrategyStateChange(
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SignalStrategy::State state) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state == SignalStrategy::CONNECTED) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!callback_.is_null());
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_ = iq_sender_->SendIq(
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        buzz::STR_SET, directory_bot_jid_,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CreateRegistrationRequest(signal_strategy_->GetLocalJid()).Pass(),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&RegisterSupportHostRequest::ProcessResponse,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   base::Unretained(this)));
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (state == SignalStrategy::DISCONNECTED) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We will reach here if signaling fails to connect.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CallCallback(false, std::string(), base::TimeDelta());
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RegisterSupportHostRequest::OnSignalStrategyIncomingStanza(
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const buzz::XmlElement* stanza) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<XmlElement> RegisterSupportHostRequest::CreateRegistrationRequest(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& jid) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<XmlElement> query(new XmlElement(
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, kRegisterQueryTag)));
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XmlElement* public_key = new XmlElement(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, kPublicKeyTag));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  public_key->AddText(key_pair_->GetPublicKey());
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query->AddElement(public_key);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query->AddElement(CreateSignature(jid).release());
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return query.Pass();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<XmlElement> RegisterSupportHostRequest::CreateSignature(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& jid) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<XmlElement> signature_tag(new XmlElement(
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, kSignatureTag)));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 time = static_cast<int64>(base::Time::Now().ToDoubleT());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string time_str(base::Int64ToString(time));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signature_tag->AddAttr(
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, kSignatureTimeAttr), time_str);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string message = jid + ' ' + time_str;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string signature(key_pair_->SignMessage(message));
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signature_tag->AddText(signature);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return signature_tag.Pass();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RegisterSupportHostRequest::ParseResponse(const XmlElement* response,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               std::string* support_id,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               base::TimeDelta* lifetime) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string type = response->Attr(buzz::QN_TYPE);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == buzz::STR_ERROR) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Received error in response to heartbeat: "
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << response->Str();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method must only be called for error or result stanzas.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type != buzz::STR_RESULT) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Received unexpect stanza of type \"" << type << "\"";
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const XmlElement* result_element = response->FirstNamed(QName(
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kChromotingXmlNamespace, kRegisterQueryResultTag));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result_element) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "<" << kRegisterQueryResultTag
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "> is missing in the host registration response: "
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << response->Str();
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const XmlElement* support_id_element =
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_element->FirstNamed(QName(kChromotingXmlNamespace, kSupportIdTag));
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!support_id_element) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "<" << kSupportIdTag
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "> is missing in the host registration response: "
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << response->Str();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const XmlElement* lifetime_element =
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_element->FirstNamed(QName(kChromotingXmlNamespace,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       kSupportIdLifetimeTag));
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!lifetime_element) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "<" << kSupportIdLifetimeTag
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "> is missing in the host registration response: "
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << response->Str();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int lifetime_int;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::StringToInt(lifetime_element->BodyText().c_str(), &lifetime_int) ||
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lifetime_int <= 0) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "<" << kSupportIdLifetimeTag
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "> is malformed in the host registration response: "
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << response->Str();
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *support_id = support_id_element->BodyText();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *lifetime = base::TimeDelta::FromSeconds(lifetime_int);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RegisterSupportHostRequest::ProcessResponse(IqRequest* request,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 const XmlElement* response) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string support_id;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta lifetime;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = ParseResponse(response, &support_id, &lifetime);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CallCallback(success, support_id, lifetime);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RegisterSupportHostRequest::CallCallback(
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success, const std::string& support_id, base::TimeDelta lifetime) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cleanup state before calling the callback.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_.reset();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iq_sender_.reset();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal_strategy_->RemoveListener(this);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal_strategy_ = NULL;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterCallback callback = callback_;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_.Reset();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(success, support_id, lifetime);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
187