| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/jingle_glue/iq_sender.h" | 5 #include "remoting/jingle_glue/iq_sender.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | |
| 8 #include "base/location.h" | |
| 9 #include "base/logging.h" | 7 #include "base/logging.h" |
| 10 #include "base/message_loop_proxy.h" | |
| 11 #include "base/string_number_conversions.h" | 8 #include "base/string_number_conversions.h" |
| 12 #include "remoting/jingle_glue/signal_strategy.h" | 9 #include "remoting/jingle_glue/signal_strategy.h" |
| 13 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" | 10 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" |
| 14 #include "third_party/libjingle/source/talk/xmpp/constants.h" | 11 #include "third_party/libjingle/source/talk/xmpp/constants.h" |
| 15 | 12 |
| 16 namespace remoting { | 13 namespace remoting { |
| 17 | 14 |
| 18 // static | 15 // static |
| 19 scoped_ptr<buzz::XmlElement> IqSender::MakeIqStanza( | 16 scoped_ptr<buzz::XmlElement> IqSender::MakeIqStanza( |
| 20 const std::string& type, | 17 const std::string& type, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 32 : signal_strategy_(signal_strategy) { | 29 : signal_strategy_(signal_strategy) { |
| 33 signal_strategy_->AddListener(this); | 30 signal_strategy_->AddListener(this); |
| 34 } | 31 } |
| 35 | 32 |
| 36 IqSender::~IqSender() { | 33 IqSender::~IqSender() { |
| 37 signal_strategy_->RemoveListener(this); | 34 signal_strategy_->RemoveListener(this); |
| 38 } | 35 } |
| 39 | 36 |
| 40 scoped_ptr<IqRequest> IqSender::SendIq(scoped_ptr<buzz::XmlElement> stanza, | 37 scoped_ptr<IqRequest> IqSender::SendIq(scoped_ptr<buzz::XmlElement> stanza, |
| 41 const ReplyCallback& callback) { | 38 const ReplyCallback& callback) { |
| 42 std::string addressee = stanza->Attr(buzz::QN_TO); | |
| 43 std::string id = signal_strategy_->GetNextId(); | 39 std::string id = signal_strategy_->GetNextId(); |
| 44 stanza->AddAttr(buzz::QN_ID, id); | 40 stanza->AddAttr(buzz::QN_ID, id); |
| 45 if (!signal_strategy_->SendStanza(stanza.Pass())) { | 41 if (!signal_strategy_->SendStanza(stanza.Pass())) { |
| 46 return scoped_ptr<IqRequest>(NULL); | 42 return scoped_ptr<IqRequest>(NULL); |
| 47 } | 43 } |
| 48 DCHECK(requests_.find(id) == requests_.end()); | 44 DCHECK(requests_.find(id) == requests_.end()); |
| 49 scoped_ptr<IqRequest> request(new IqRequest(this, callback, addressee)); | 45 scoped_ptr<IqRequest> request(new IqRequest(this, callback)); |
| 50 if (!callback.is_null()) | 46 if (!callback.is_null()) |
| 51 requests_[id] = request.get(); | 47 requests_[id] = request.get(); |
| 52 return request.Pass(); | 48 return request.Pass(); |
| 53 } | 49 } |
| 54 | 50 |
| 55 scoped_ptr<IqRequest> IqSender::SendIq(const std::string& type, | 51 scoped_ptr<IqRequest> IqSender::SendIq(const std::string& type, |
| 56 const std::string& addressee, | 52 const std::string& addressee, |
| 57 scoped_ptr<buzz::XmlElement> iq_body, | 53 scoped_ptr<buzz::XmlElement> iq_body, |
| 58 const ReplyCallback& callback) { | 54 const ReplyCallback& callback) { |
| 59 return SendIq(MakeIqStanza(type, addressee, iq_body.Pass()), callback); | 55 return SendIq(MakeIqStanza(type, addressee, iq_body.Pass()), callback); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 89 if (type != "result" && type != "error") { | 85 if (type != "result" && type != "error") { |
| 90 return false; | 86 return false; |
| 91 } | 87 } |
| 92 | 88 |
| 93 const std::string& id = stanza->Attr(buzz::QN_ID); | 89 const std::string& id = stanza->Attr(buzz::QN_ID); |
| 94 if (id.empty()) { | 90 if (id.empty()) { |
| 95 LOG(WARNING) << "IQ packet missing id " << stanza->Str(); | 91 LOG(WARNING) << "IQ packet missing id " << stanza->Str(); |
| 96 return false; | 92 return false; |
| 97 } | 93 } |
| 98 | 94 |
| 99 std::string from = stanza->Attr(buzz::QN_FROM); | |
| 100 | |
| 101 IqRequestMap::iterator it = requests_.find(id); | 95 IqRequestMap::iterator it = requests_.find(id); |
| 102 | |
| 103 // This is a hack to workaround the issue with the WCS changing IDs | |
| 104 // of IQ responses sent from client to host. Whenever we receive a | |
| 105 // stanza with an unknown ID we try to match it with an outstanding | |
| 106 // request sent to the same peer. | |
| 107 if (it == requests_.end()) { | |
| 108 for (it = requests_.begin(); it != requests_.end(); ++it) { | |
| 109 if (it->second->addressee_ == from) { | |
| 110 break; | |
| 111 } | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 if (it == requests_.end()) { | 96 if (it == requests_.end()) { |
| 116 return false; | 97 return false; |
| 117 } | 98 } |
| 118 | 99 |
| 119 IqRequest* request = it->second; | 100 IqRequest* request = it->second; |
| 101 requests_.erase(it); |
| 120 | 102 |
| 121 if (request->addressee_ != from) { | |
| 122 LOG(ERROR) << "Received IQ response from from a invalid JID. Ignoring it." | |
| 123 << " Message received from: " << from | |
| 124 << " Original JID: " << request->addressee_; | |
| 125 return false; | |
| 126 } | |
| 127 | |
| 128 requests_.erase(it); | |
| 129 request->OnResponse(stanza); | 103 request->OnResponse(stanza); |
| 130 | |
| 131 return true; | 104 return true; |
| 132 } | 105 } |
| 133 | 106 |
| 134 IqRequest::IqRequest(IqSender* sender, const IqSender::ReplyCallback& callback, | 107 IqRequest::IqRequest(IqSender* sender, const IqSender::ReplyCallback& callback) |
| 135 const std::string& addressee) | |
| 136 : sender_(sender), | 108 : sender_(sender), |
| 137 callback_(callback), | 109 callback_(callback) { |
| 138 addressee_(addressee) { | |
| 139 } | 110 } |
| 140 | 111 |
| 141 IqRequest::~IqRequest() { | 112 IqRequest::~IqRequest() { |
| 142 sender_->RemoveRequest(this); | 113 sender_->RemoveRequest(this); |
| 143 } | 114 } |
| 144 | 115 |
| 145 void IqRequest::SetTimeout(base::TimeDelta timeout) { | |
| 146 base::MessageLoopProxy::current()->PostDelayedTask( | |
| 147 FROM_HERE, base::Bind(&IqRequest::OnTimeout, AsWeakPtr()), | |
| 148 timeout.InMilliseconds()); | |
| 149 } | |
| 150 | |
| 151 void IqRequest::CallCallback(const buzz::XmlElement* stanza) { | |
| 152 if (!callback_.is_null()) { | |
| 153 IqSender::ReplyCallback callback(callback_); | |
| 154 callback_.Reset(); | |
| 155 callback.Run(this, stanza); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 void IqRequest::OnTimeout() { | |
| 160 CallCallback(NULL); | |
| 161 } | |
| 162 | |
| 163 void IqRequest::OnResponse(const buzz::XmlElement* stanza) { | 116 void IqRequest::OnResponse(const buzz::XmlElement* stanza) { |
| 164 CallCallback(stanza); | 117 DCHECK(!callback_.is_null()); |
| 118 IqSender::ReplyCallback callback(callback_); |
| 119 callback_.Reset(); |
| 120 callback.Run(stanza); |
| 165 } | 121 } |
| 166 | 122 |
| 167 } // namespace remoting | 123 } // namespace remoting |
| OLD | NEW |