OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "remoting/jingle_glue/iq_sender.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/location.h" | |
9 #include "base/logging.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/single_thread_task_runner.h" | |
12 #include "base/strings/string_number_conversions.h" | |
13 #include "base/thread_task_runner_handle.h" | |
14 #include "base/time/time.h" | |
15 #include "remoting/jingle_glue/signal_strategy.h" | |
16 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" | |
17 #include "third_party/libjingle/source/talk/xmpp/constants.h" | |
18 | |
19 namespace remoting { | |
20 | |
21 // static | |
22 scoped_ptr<buzz::XmlElement> IqSender::MakeIqStanza( | |
23 const std::string& type, | |
24 const std::string& addressee, | |
25 scoped_ptr<buzz::XmlElement> iq_body) { | |
26 scoped_ptr<buzz::XmlElement> stanza(new buzz::XmlElement(buzz::QN_IQ)); | |
27 stanza->AddAttr(buzz::QN_TYPE, type); | |
28 if (!addressee.empty()) | |
29 stanza->AddAttr(buzz::QN_TO, addressee); | |
30 stanza->AddElement(iq_body.release()); | |
31 return stanza.Pass(); | |
32 } | |
33 | |
34 IqSender::IqSender(SignalStrategy* signal_strategy) | |
35 : signal_strategy_(signal_strategy) { | |
36 signal_strategy_->AddListener(this); | |
37 } | |
38 | |
39 IqSender::~IqSender() { | |
40 signal_strategy_->RemoveListener(this); | |
41 } | |
42 | |
43 scoped_ptr<IqRequest> IqSender::SendIq(scoped_ptr<buzz::XmlElement> stanza, | |
44 const ReplyCallback& callback) { | |
45 std::string addressee = stanza->Attr(buzz::QN_TO); | |
46 std::string id = signal_strategy_->GetNextId(); | |
47 stanza->AddAttr(buzz::QN_ID, id); | |
48 if (!signal_strategy_->SendStanza(stanza.Pass())) { | |
49 return scoped_ptr<IqRequest>(); | |
50 } | |
51 DCHECK(requests_.find(id) == requests_.end()); | |
52 scoped_ptr<IqRequest> request(new IqRequest(this, callback, addressee)); | |
53 if (!callback.is_null()) | |
54 requests_[id] = request.get(); | |
55 return request.Pass(); | |
56 } | |
57 | |
58 scoped_ptr<IqRequest> IqSender::SendIq(const std::string& type, | |
59 const std::string& addressee, | |
60 scoped_ptr<buzz::XmlElement> iq_body, | |
61 const ReplyCallback& callback) { | |
62 return SendIq(MakeIqStanza(type, addressee, iq_body.Pass()), callback); | |
63 } | |
64 | |
65 void IqSender::RemoveRequest(IqRequest* request) { | |
66 IqRequestMap::iterator it = requests_.begin(); | |
67 while (it != requests_.end()) { | |
68 IqRequestMap::iterator cur = it; | |
69 ++it; | |
70 if (cur->second == request) { | |
71 requests_.erase(cur); | |
72 break; | |
73 } | |
74 } | |
75 } | |
76 | |
77 void IqSender::OnSignalStrategyStateChange(SignalStrategy::State state) { | |
78 } | |
79 | |
80 bool IqSender::OnSignalStrategyIncomingStanza(const buzz::XmlElement* stanza) { | |
81 if (stanza->Name() != buzz::QN_IQ) { | |
82 LOG(WARNING) << "Received unexpected non-IQ packet " << stanza->Str(); | |
83 return false; | |
84 } | |
85 | |
86 const std::string& type = stanza->Attr(buzz::QN_TYPE); | |
87 if (type.empty()) { | |
88 LOG(WARNING) << "IQ packet missing type " << stanza->Str(); | |
89 return false; | |
90 } | |
91 | |
92 if (type != "result" && type != "error") { | |
93 return false; | |
94 } | |
95 | |
96 const std::string& id = stanza->Attr(buzz::QN_ID); | |
97 if (id.empty()) { | |
98 LOG(WARNING) << "IQ packet missing id " << stanza->Str(); | |
99 return false; | |
100 } | |
101 | |
102 std::string from = stanza->Attr(buzz::QN_FROM); | |
103 | |
104 IqRequestMap::iterator it = requests_.find(id); | |
105 if (it == requests_.end()) { | |
106 return false; | |
107 } | |
108 | |
109 IqRequest* request = it->second; | |
110 | |
111 if (request->addressee_ != from) { | |
112 LOG(ERROR) << "Received IQ response from from a invalid JID. Ignoring it." | |
113 << " Message received from: " << from | |
114 << " Original JID: " << request->addressee_; | |
115 return false; | |
116 } | |
117 | |
118 requests_.erase(it); | |
119 request->OnResponse(stanza); | |
120 | |
121 return true; | |
122 } | |
123 | |
124 IqRequest::IqRequest(IqSender* sender, const IqSender::ReplyCallback& callback, | |
125 const std::string& addressee) | |
126 : sender_(sender), | |
127 callback_(callback), | |
128 addressee_(addressee) { | |
129 } | |
130 | |
131 IqRequest::~IqRequest() { | |
132 sender_->RemoveRequest(this); | |
133 } | |
134 | |
135 void IqRequest::SetTimeout(base::TimeDelta timeout) { | |
136 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
137 FROM_HERE, base::Bind(&IqRequest::OnTimeout, AsWeakPtr()), timeout); | |
138 } | |
139 | |
140 void IqRequest::CallCallback(const buzz::XmlElement* stanza) { | |
141 if (!callback_.is_null()) { | |
142 IqSender::ReplyCallback callback(callback_); | |
143 callback_.Reset(); | |
144 callback.Run(this, stanza); | |
145 } | |
146 } | |
147 | |
148 void IqRequest::OnTimeout() { | |
149 CallCallback(NULL); | |
150 } | |
151 | |
152 void IqRequest::OnResponse(const buzz::XmlElement* stanza) { | |
153 // It's unsafe to delete signal strategy here, and the callback may | |
154 // want to do that, so we post task to invoke the callback later. | |
155 scoped_ptr<buzz::XmlElement> stanza_copy(new buzz::XmlElement(*stanza)); | |
156 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
157 FROM_HERE, base::Bind(&IqRequest::DeliverResponse, AsWeakPtr(), | |
158 base::Passed(&stanza_copy))); | |
159 } | |
160 | |
161 void IqRequest::DeliverResponse(scoped_ptr<buzz::XmlElement> stanza) { | |
162 CallCallback(stanza.get()); | |
163 } | |
164 | |
165 } // namespace remoting | |
OLD | NEW |