Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1029)

Side by Side Diff: third_party/libjingle_xmpp/xmpp/xmppengineimpl.cc

Issue 2443903004: Add xmllite and xmpp sources to third_party/ (Closed)
Patch Set: Fix GN and sort includes Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2004 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 "third_party/libjingle_xmpp/xmpp/xmppengineimpl.h"
6
7 #include <algorithm>
8 #include <sstream>
9 #include <vector>
10
11 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
12 #include "third_party/libjingle_xmpp/xmllite/xmlprinter.h"
13 #include "third_party/libjingle_xmpp/xmpp/constants.h"
14 #include "third_party/libjingle_xmpp/xmpp/saslhandler.h"
15 #include "third_party/libjingle_xmpp/xmpp/xmpplogintask.h"
16 #include "webrtc/base/common.h"
17
18 namespace buzz {
19
20 XmppEngine* XmppEngine::Create() {
21 return new XmppEngineImpl();
22 }
23
24
25 XmppEngineImpl::XmppEngineImpl()
26 : stanza_parse_handler_(this),
27 stanza_parser_(&stanza_parse_handler_),
28 engine_entered_(0),
29 password_(),
30 requested_resource_(STR_EMPTY),
31 tls_option_(buzz::TLS_REQUIRED),
32 login_task_(new XmppLoginTask(this)),
33 next_id_(0),
34 state_(STATE_START),
35 encrypted_(false),
36 error_code_(ERROR_NONE),
37 subcode_(0),
38 stream_error_(),
39 raised_reset_(false),
40 output_handler_(NULL),
41 session_handler_(NULL),
42 iq_entries_(new IqEntryVector()),
43 sasl_handler_(),
44 output_(new std::stringstream()) {
45 for (int i = 0; i < HL_COUNT; i+= 1) {
46 stanza_handlers_[i].reset(new StanzaHandlerVector());
47 }
48
49 // Add XMPP namespaces to XML namespaces stack.
50 xmlns_stack_.AddXmlns("stream", "http://etherx.jabber.org/streams");
51 xmlns_stack_.AddXmlns("", "jabber:client");
52 }
53
54 XmppEngineImpl::~XmppEngineImpl() {
55 DeleteIqCookies();
56 }
57
58 XmppReturnStatus XmppEngineImpl::SetOutputHandler(
59 XmppOutputHandler* output_handler) {
60 if (state_ != STATE_START)
61 return XMPP_RETURN_BADSTATE;
62
63 output_handler_ = output_handler;
64
65 return XMPP_RETURN_OK;
66 }
67
68 XmppReturnStatus XmppEngineImpl::SetSessionHandler(
69 XmppSessionHandler* session_handler) {
70 if (state_ != STATE_START)
71 return XMPP_RETURN_BADSTATE;
72
73 session_handler_ = session_handler;
74
75 return XMPP_RETURN_OK;
76 }
77
78 XmppReturnStatus XmppEngineImpl::HandleInput(
79 const char* bytes, size_t len) {
80 if (state_ < STATE_OPENING || state_ > STATE_OPEN)
81 return XMPP_RETURN_BADSTATE;
82
83 EnterExit ee(this);
84
85 // TODO: The return value of the xml parser is not checked.
86 stanza_parser_.Parse(bytes, len, false);
87
88 return XMPP_RETURN_OK;
89 }
90
91 XmppReturnStatus XmppEngineImpl::ConnectionClosed(int subcode) {
92 if (state_ != STATE_CLOSED) {
93 EnterExit ee(this);
94 // If told that connection closed and not already closed,
95 // then connection was unpexectedly dropped.
96 if (subcode) {
97 SignalError(ERROR_SOCKET, subcode);
98 } else {
99 SignalError(ERROR_CONNECTION_CLOSED, 0); // no subcode
100 }
101 }
102 return XMPP_RETURN_OK;
103 }
104
105 XmppReturnStatus XmppEngineImpl::SetTls(TlsOptions use_tls) {
106 if (state_ != STATE_START)
107 return XMPP_RETURN_BADSTATE;
108 tls_option_ = use_tls;
109 return XMPP_RETURN_OK;
110 }
111
112 XmppReturnStatus XmppEngineImpl::SetTlsServer(
113 const std::string& tls_server_hostname,
114 const std::string& tls_server_domain) {
115 if (state_ != STATE_START)
116 return XMPP_RETURN_BADSTATE;
117
118 tls_server_hostname_ = tls_server_hostname;
119 tls_server_domain_= tls_server_domain;
120
121 return XMPP_RETURN_OK;
122 }
123
124 TlsOptions XmppEngineImpl::GetTls() {
125 return tls_option_;
126 }
127
128 XmppReturnStatus XmppEngineImpl::SetUser(const Jid& jid) {
129 if (state_ != STATE_START)
130 return XMPP_RETURN_BADSTATE;
131
132 user_jid_ = jid;
133
134 return XMPP_RETURN_OK;
135 }
136
137 const Jid& XmppEngineImpl::GetUser() {
138 return user_jid_;
139 }
140
141 XmppReturnStatus XmppEngineImpl::SetSaslHandler(SaslHandler* sasl_handler) {
142 if (state_ != STATE_START)
143 return XMPP_RETURN_BADSTATE;
144
145 sasl_handler_.reset(sasl_handler);
146 return XMPP_RETURN_OK;
147 }
148
149 XmppReturnStatus XmppEngineImpl::SetRequestedResource(
150 const std::string& resource) {
151 if (state_ != STATE_START)
152 return XMPP_RETURN_BADSTATE;
153
154 requested_resource_ = resource;
155
156 return XMPP_RETURN_OK;
157 }
158
159 const std::string& XmppEngineImpl::GetRequestedResource() {
160 return requested_resource_;
161 }
162
163 XmppReturnStatus XmppEngineImpl::AddStanzaHandler(
164 XmppStanzaHandler* stanza_handler,
165 XmppEngine::HandlerLevel level) {
166 if (state_ == STATE_CLOSED)
167 return XMPP_RETURN_BADSTATE;
168
169 stanza_handlers_[level]->push_back(stanza_handler);
170
171 return XMPP_RETURN_OK;
172 }
173
174 XmppReturnStatus XmppEngineImpl::RemoveStanzaHandler(
175 XmppStanzaHandler* stanza_handler) {
176 bool found = false;
177
178 for (int level = 0; level < HL_COUNT; level += 1) {
179 StanzaHandlerVector::iterator new_end =
180 std::remove(stanza_handlers_[level]->begin(),
181 stanza_handlers_[level]->end(),
182 stanza_handler);
183
184 if (new_end != stanza_handlers_[level]->end()) {
185 stanza_handlers_[level]->erase(new_end, stanza_handlers_[level]->end());
186 found = true;
187 }
188 }
189
190 if (!found)
191 return XMPP_RETURN_BADARGUMENT;
192
193 return XMPP_RETURN_OK;
194 }
195
196 XmppReturnStatus XmppEngineImpl::Connect() {
197 if (state_ != STATE_START)
198 return XMPP_RETURN_BADSTATE;
199
200 EnterExit ee(this);
201
202 // get the login task started
203 state_ = STATE_OPENING;
204 if (login_task_) {
205 login_task_->IncomingStanza(NULL, false);
206 if (login_task_->IsDone())
207 login_task_.reset();
208 }
209
210 return XMPP_RETURN_OK;
211 }
212
213 XmppReturnStatus XmppEngineImpl::SendStanza(const XmlElement* element) {
214 if (state_ == STATE_CLOSED)
215 return XMPP_RETURN_BADSTATE;
216
217 EnterExit ee(this);
218
219 if (login_task_) {
220 // still handshaking - then outbound stanzas are queued
221 login_task_->OutgoingStanza(element);
222 } else {
223 // handshake done - send straight through
224 InternalSendStanza(element);
225 }
226
227 return XMPP_RETURN_OK;
228 }
229
230 XmppReturnStatus XmppEngineImpl::SendRaw(const std::string& text) {
231 if (state_ == STATE_CLOSED || login_task_)
232 return XMPP_RETURN_BADSTATE;
233
234 EnterExit ee(this);
235
236 (*output_) << text;
237
238 return XMPP_RETURN_OK;
239 }
240
241 std::string XmppEngineImpl::NextId() {
242 std::stringstream ss;
243 ss << next_id_++;
244 return ss.str();
245 }
246
247 XmppReturnStatus XmppEngineImpl::Disconnect() {
248 if (state_ != STATE_CLOSED) {
249 EnterExit ee(this);
250 if (state_ == STATE_OPEN)
251 *output_ << "</stream:stream>";
252 state_ = STATE_CLOSED;
253 }
254
255 return XMPP_RETURN_OK;
256 }
257
258 void XmppEngineImpl::IncomingStart(const XmlElement* start) {
259 if (HasError() || raised_reset_)
260 return;
261
262 if (login_task_) {
263 // start-stream should go to login task
264 login_task_->IncomingStanza(start, true);
265 if (login_task_->IsDone())
266 login_task_.reset();
267 }
268 else {
269 // if not logging in, it's an error to see a start
270 SignalError(ERROR_XML, 0);
271 }
272 }
273
274 void XmppEngineImpl::IncomingStanza(const XmlElement* stanza) {
275 if (HasError() || raised_reset_)
276 return;
277
278 if (stanza->Name() == QN_STREAM_ERROR) {
279 // Explicit XMPP stream error
280 SignalStreamError(stanza);
281 } else if (login_task_) {
282 // Handle login handshake
283 login_task_->IncomingStanza(stanza, false);
284 if (login_task_->IsDone())
285 login_task_.reset();
286 } else if (HandleIqResponse(stanza)) {
287 // iq is handled by above call
288 } else {
289 // give every "peek" handler a shot at all stanzas
290 for (size_t i = 0; i < stanza_handlers_[HL_PEEK]->size(); i += 1) {
291 (*stanza_handlers_[HL_PEEK])[i]->HandleStanza(stanza);
292 }
293
294 // give other handlers a shot in precedence order, stopping after handled
295 for (int level = HL_SINGLE; level <= HL_ALL; level += 1) {
296 for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) {
297 if ((*stanza_handlers_[level])[i]->HandleStanza(stanza))
298 return;
299 }
300 }
301
302 // If nobody wants to handle a stanza then send back an error.
303 // Only do this for IQ stanzas as messages should probably just be dropped
304 // and presence stanzas should certainly be dropped.
305 std::string type = stanza->Attr(QN_TYPE);
306 if (stanza->Name() == QN_IQ &&
307 !(type == "error" || type == "result")) {
308 SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY);
309 }
310 }
311 }
312
313 void XmppEngineImpl::IncomingEnd(bool isError) {
314 if (HasError() || raised_reset_)
315 return;
316
317 SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED, 0);
318 }
319
320 void XmppEngineImpl::InternalSendStart(const std::string& to) {
321 std::string hostname = tls_server_hostname_;
322 if (hostname.empty())
323 hostname = to;
324
325 // If not language is specified, the spec says use *
326 std::string lang = lang_;
327 if (lang.length() == 0)
328 lang = "*";
329
330 // send stream-beginning
331 // note, we put a \r\n at tne end fo the first line to cause non-XMPP
332 // line-oriented servers (e.g., Apache) to reveal themselves more quickly.
333 *output_ << "<stream:stream to=\"" << hostname << "\" "
334 << "xml:lang=\"" << lang << "\" "
335 << "version=\"1.0\" "
336 << "xmlns:stream=\"http://etherx.jabber.org/streams\" "
337 << "xmlns=\"jabber:client\">\r\n";
338 }
339
340 void XmppEngineImpl::InternalSendStanza(const XmlElement* element) {
341 // It should really never be necessary to set a FROM attribute on a stanza.
342 // It is implied by the bind on the stream and if you get it wrong
343 // (by flipping from/to on a message?) the server will close the stream.
344 ASSERT(!element->HasAttr(QN_FROM));
345
346 XmlPrinter::PrintXml(output_.get(), element, &xmlns_stack_);
347 }
348
349 std::string XmppEngineImpl::ChooseBestSaslMechanism(
350 const std::vector<std::string>& mechanisms, bool encrypted) {
351 return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted);
352 }
353
354 SaslMechanism* XmppEngineImpl::GetSaslMechanism(const std::string& name) {
355 return sasl_handler_->CreateSaslMechanism(name);
356 }
357
358 void XmppEngineImpl::SignalBound(const Jid& fullJid) {
359 if (state_ == STATE_OPENING) {
360 bound_jid_ = fullJid;
361 state_ = STATE_OPEN;
362 }
363 }
364
365 void XmppEngineImpl::SignalStreamError(const XmlElement* stream_error) {
366 if (state_ != STATE_CLOSED) {
367 stream_error_.reset(new XmlElement(*stream_error));
368 SignalError(ERROR_STREAM, 0);
369 }
370 }
371
372 void XmppEngineImpl::SignalError(Error error_code, int sub_code) {
373 if (state_ != STATE_CLOSED) {
374 error_code_ = error_code;
375 subcode_ = sub_code;
376 state_ = STATE_CLOSED;
377 }
378 }
379
380 bool XmppEngineImpl::HasError() {
381 return error_code_ != ERROR_NONE;
382 }
383
384 void XmppEngineImpl::StartTls(const std::string& domain) {
385 if (output_handler_) {
386 // As substitute for the real (login jid's) domain, we permit
387 // verifying a tls_server_domain_ instead, if one was passed.
388 // This allows us to avoid running a proxy that needs to handle
389 // valuable certificates.
390 output_handler_->StartTls(
391 tls_server_domain_.empty() ? domain : tls_server_domain_);
392 encrypted_ = true;
393 }
394 }
395
396 XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine)
397 : engine_(engine),
398 state_(engine->state_) {
399 engine->engine_entered_ += 1;
400 }
401
402 XmppEngineImpl::EnterExit::~EnterExit() {
403 XmppEngineImpl* engine = engine_;
404
405 engine->engine_entered_ -= 1;
406
407 bool closing = (engine->state_ != state_ &&
408 engine->state_ == STATE_CLOSED);
409 bool flushing = closing || (engine->engine_entered_ == 0);
410
411 if (engine->output_handler_ && flushing) {
412 std::string output = engine->output_->str();
413 if (output.length() > 0)
414 engine->output_handler_->WriteOutput(output.c_str(), output.length());
415 engine->output_->str("");
416
417 if (closing) {
418 engine->output_handler_->CloseConnection();
419 engine->output_handler_ = 0;
420 }
421 }
422
423 if (engine->engine_entered_)
424 return;
425
426 if (engine->raised_reset_) {
427 engine->stanza_parser_.Reset();
428 engine->raised_reset_ = false;
429 }
430
431 if (engine->session_handler_) {
432 if (engine->state_ != state_)
433 engine->session_handler_->OnStateChange(engine->state_);
434 // Note: Handling of OnStateChange(CLOSED) should allow for the
435 // deletion of the engine, so no members should be accessed
436 // after this line.
437 }
438 }
439
440 } // namespace buzz
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698