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