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

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

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

Powered by Google App Engine
This is Rietveld 408576698