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

Side by Side Diff: third_party/libjingle_xmpp/xmpp/xmppclient.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/xmppclient.h"
12
13 #include "third_party/libjingle_xmpp/xmpp/constants.h"
14 #include "third_party/libjingle_xmpp/xmpp/plainsaslhandler.h"
15 #include "third_party/libjingle_xmpp/xmpp/prexmppauth.h"
16 #include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
17 #include "third_party/webrtc/base/sigslot.h"
18 #include "third_party/webrtc/base/stringutils.h"
19 #include "third_party/webrtc_overrides/webrtc/base/logging.h"
20 #include "xmpptask.h"
21
22 namespace buzz {
23
24 class XmppClient::Private :
25 public sigslot::has_slots<>,
26 public XmppSessionHandler,
27 public XmppOutputHandler {
28 public:
29
30 explicit Private(XmppClient* client) :
31 client_(client),
32 socket_(),
33 engine_(),
34 proxy_port_(0),
35 pre_engine_error_(XmppEngine::ERROR_NONE),
36 pre_engine_subcode_(0),
37 signal_closed_(false),
38 allow_plain_(false) {}
39
40 virtual ~Private() {
41 // We need to disconnect from socket_ before engine_ is destructed (by
42 // the auto-generated destructor code).
43 ResetSocket();
44 }
45
46 // the owner
47 XmppClient* const client_;
48
49 // the two main objects
50 std::unique_ptr<AsyncSocket> socket_;
51 std::unique_ptr<XmppEngine> engine_;
52 std::unique_ptr<PreXmppAuth> pre_auth_;
53 rtc::CryptString pass_;
54 std::string auth_mechanism_;
55 std::string auth_token_;
56 rtc::SocketAddress server_;
57 std::string proxy_host_;
58 int proxy_port_;
59 XmppEngine::Error pre_engine_error_;
60 int pre_engine_subcode_;
61 CaptchaChallenge captcha_challenge_;
62 bool signal_closed_;
63 bool allow_plain_;
64
65 void ResetSocket() {
66 if (socket_) {
67 socket_->SignalConnected.disconnect(this);
68 socket_->SignalRead.disconnect(this);
69 socket_->SignalClosed.disconnect(this);
70 socket_.reset(NULL);
71 }
72 }
73
74 // implementations of interfaces
75 void OnStateChange(int state);
76 void WriteOutput(const char* bytes, size_t len);
77 void StartTls(const std::string& domainname);
78 void CloseConnection();
79
80 // slots for socket signals
81 void OnSocketConnected();
82 void OnSocketRead();
83 void OnSocketClosed();
84 };
85
86 bool IsTestServer(const std::string& server_name,
87 const std::string& test_server_domain) {
88 return (!test_server_domain.empty() &&
89 rtc::ends_with(server_name.c_str(),
90 test_server_domain.c_str()));
91 }
92
93 XmppReturnStatus XmppClient::Connect(
94 const XmppClientSettings& settings,
95 const std::string& lang, AsyncSocket* socket, PreXmppAuth* pre_auth) {
96 if (socket == NULL)
97 return XMPP_RETURN_BADARGUMENT;
98 if (d_->socket_)
99 return XMPP_RETURN_BADSTATE;
100
101 d_->socket_.reset(socket);
102
103 d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected);
104 d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead);
105 d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed);
106
107 d_->engine_.reset(XmppEngine::Create());
108 d_->engine_->SetSessionHandler(d_.get());
109 d_->engine_->SetOutputHandler(d_.get());
110 if (!settings.resource().empty()) {
111 d_->engine_->SetRequestedResource(settings.resource());
112 }
113 d_->engine_->SetTls(settings.use_tls());
114
115 // The talk.google.com server returns a certificate with common-name:
116 // CN="gmail.com" for @gmail.com accounts,
117 // CN="googlemail.com" for @googlemail.com accounts,
118 // CN="talk.google.com" for other accounts (such as @example.com),
119 // so we tweak the tls server setting for those other accounts to match the
120 // returned certificate CN of "talk.google.com".
121 // For other servers, we leave the strings empty, which causes the jid's
122 // domain to be used. We do the same for gmail.com and googlemail.com as the
123 // returned CN matches the account domain in those cases.
124 std::string server_name = settings.server().HostAsURIString();
125 if (server_name == buzz::STR_TALK_GOOGLE_COM ||
126 server_name == buzz::STR_TALKX_L_GOOGLE_COM ||
127 server_name == buzz::STR_XMPP_GOOGLE_COM ||
128 server_name == buzz::STR_XMPPX_L_GOOGLE_COM ||
129 IsTestServer(server_name, settings.test_server_domain())) {
130 if (settings.host() != STR_GMAIL_COM &&
131 settings.host() != STR_GOOGLEMAIL_COM) {
132 d_->engine_->SetTlsServer("", STR_TALK_GOOGLE_COM);
133 }
134 }
135
136 // Set language
137 d_->engine_->SetLanguage(lang);
138
139 d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY));
140
141 d_->pass_ = settings.pass();
142 d_->auth_mechanism_ = settings.auth_mechanism();
143 d_->auth_token_ = settings.auth_token();
144 d_->server_ = settings.server();
145 d_->proxy_host_ = settings.proxy_host();
146 d_->proxy_port_ = settings.proxy_port();
147 d_->allow_plain_ = settings.allow_plain();
148 d_->pre_auth_.reset(pre_auth);
149
150 return XMPP_RETURN_OK;
151 }
152
153 XmppEngine::State XmppClient::GetState() const {
154 if (!d_->engine_)
155 return XmppEngine::STATE_NONE;
156 return d_->engine_->GetState();
157 }
158
159 XmppEngine::Error XmppClient::GetError(int* subcode) {
160 if (subcode) {
161 *subcode = 0;
162 }
163 if (!d_->engine_)
164 return XmppEngine::ERROR_NONE;
165 if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE) {
166 if (subcode) {
167 *subcode = d_->pre_engine_subcode_;
168 }
169 return d_->pre_engine_error_;
170 }
171 return d_->engine_->GetError(subcode);
172 }
173
174 const XmlElement* XmppClient::GetStreamError() {
175 if (!d_->engine_) {
176 return NULL;
177 }
178 return d_->engine_->GetStreamError();
179 }
180
181 CaptchaChallenge XmppClient::GetCaptchaChallenge() {
182 if (!d_->engine_)
183 return CaptchaChallenge();
184 return d_->captcha_challenge_;
185 }
186
187 std::string XmppClient::GetAuthMechanism() {
188 if (!d_->engine_)
189 return "";
190 return d_->auth_mechanism_;
191 }
192
193 std::string XmppClient::GetAuthToken() {
194 if (!d_->engine_)
195 return "";
196 return d_->auth_token_;
197 }
198
199 int XmppClient::ProcessStart() {
200 // Should not happen, but was observed in crash reports
201 if (!d_->socket_) {
202 LOG(LS_ERROR) << "socket_ already reset";
203 return STATE_DONE;
204 }
205
206 if (d_->pre_auth_) {
207 d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone);
208 d_->pre_auth_->StartPreXmppAuth(
209 d_->engine_->GetUser(), d_->server_, d_->pass_,
210 d_->auth_mechanism_, d_->auth_token_);
211 d_->pass_.Clear(); // done with this;
212 return STATE_PRE_XMPP_LOGIN;
213 }
214 else {
215 d_->engine_->SetSaslHandler(new PlainSaslHandler(
216 d_->engine_->GetUser(), d_->pass_, d_->allow_plain_));
217 d_->pass_.Clear(); // done with this;
218 return STATE_START_XMPP_LOGIN;
219 }
220 }
221
222 void XmppClient::OnAuthDone() {
223 Wake();
224 }
225
226 int XmppClient::ProcessTokenLogin() {
227 // Should not happen, but was observed in crash reports
228 if (!d_->socket_) {
229 LOG(LS_ERROR) << "socket_ already reset";
230 return STATE_DONE;
231 }
232
233 // Don't know how this could happen, but crash reports show it as NULL
234 if (!d_->pre_auth_) {
235 d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
236 EnsureClosed();
237 return STATE_ERROR;
238 }
239
240 // Wait until pre authentication is done is done
241 if (!d_->pre_auth_->IsAuthDone())
242 return STATE_BLOCKED;
243
244 if (!d_->pre_auth_->IsAuthorized()) {
245 // maybe split out a case when gaia is down?
246 if (d_->pre_auth_->HadError()) {
247 d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
248 d_->pre_engine_subcode_ = d_->pre_auth_->GetError();
249 }
250 else {
251 d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED;
252 d_->pre_engine_subcode_ = 0;
253 d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge();
254 }
255 d_->pre_auth_.reset(NULL); // done with this
256 EnsureClosed();
257 return STATE_ERROR;
258 }
259
260 // Save auth token as a result
261
262 d_->auth_mechanism_ = d_->pre_auth_->GetAuthMechanism();
263 d_->auth_token_ = d_->pre_auth_->GetAuthToken();
264
265 // transfer ownership of pre_auth_ to engine
266 d_->engine_->SetSaslHandler(d_->pre_auth_.release());
267 return STATE_START_XMPP_LOGIN;
268 }
269
270 int XmppClient::ProcessStartXmppLogin() {
271 // Should not happen, but was observed in crash reports
272 if (!d_->socket_) {
273 LOG(LS_ERROR) << "socket_ already reset";
274 return STATE_DONE;
275 }
276
277 // Done with pre-connect tasks - connect!
278 if (!d_->socket_->Connect(d_->server_)) {
279 EnsureClosed();
280 return STATE_ERROR;
281 }
282
283 return STATE_RESPONSE;
284 }
285
286 int XmppClient::ProcessResponse() {
287 // Hang around while we are connected.
288 if (!delivering_signal_ &&
289 (!d_->engine_ || d_->engine_->GetState() == XmppEngine::STATE_CLOSED))
290 return STATE_DONE;
291 return STATE_BLOCKED;
292 }
293
294 XmppReturnStatus XmppClient::Disconnect() {
295 if (!d_->socket_)
296 return XMPP_RETURN_BADSTATE;
297 Abort();
298 d_->engine_->Disconnect();
299 d_->ResetSocket();
300 return XMPP_RETURN_OK;
301 }
302
303 XmppClient::XmppClient(TaskParent* parent)
304 : XmppTaskParentInterface(parent),
305 delivering_signal_(false),
306 valid_(false) {
307 d_.reset(new Private(this));
308 valid_ = true;
309 }
310
311 XmppClient::~XmppClient() {
312 valid_ = false;
313 }
314
315 const Jid& XmppClient::jid() const {
316 return d_->engine_->FullJid();
317 }
318
319
320 std::string XmppClient::NextId() {
321 return d_->engine_->NextId();
322 }
323
324 XmppReturnStatus XmppClient::SendStanza(const XmlElement* stanza) {
325 return d_->engine_->SendStanza(stanza);
326 }
327
328 XmppReturnStatus XmppClient::SendStanzaError(
329 const XmlElement* old_stanza, XmppStanzaError xse,
330 const std::string& message) {
331 return d_->engine_->SendStanzaError(old_stanza, xse, message);
332 }
333
334 XmppReturnStatus XmppClient::SendRaw(const std::string& text) {
335 return d_->engine_->SendRaw(text);
336 }
337
338 XmppEngine* XmppClient::engine() {
339 return d_->engine_.get();
340 }
341
342 void XmppClient::Private::OnSocketConnected() {
343 engine_->Connect();
344 }
345
346 void XmppClient::Private::OnSocketRead() {
347 char bytes[4096];
348 size_t bytes_read;
349 for (;;) {
350 // Should not happen, but was observed in crash reports
351 if (!socket_) {
352 LOG(LS_ERROR) << "socket_ already reset";
353 return;
354 }
355
356 if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) {
357 // TODO: deal with error information
358 return;
359 }
360
361 if (bytes_read == 0)
362 return;
363
364 //#if !defined(NDEBUG)
365 client_->SignalLogInput(bytes, static_cast<int>(bytes_read));
366 //#endif
367
368 engine_->HandleInput(bytes, bytes_read);
369 }
370 }
371
372 void XmppClient::Private::OnSocketClosed() {
373 int code = socket_->GetError();
374 engine_->ConnectionClosed(code);
375 }
376
377 void XmppClient::Private::OnStateChange(int state) {
378 if (state == XmppEngine::STATE_CLOSED) {
379 client_->EnsureClosed();
380 }
381 else {
382 client_->SignalStateChange((XmppEngine::State)state);
383 }
384 client_->Wake();
385 }
386
387 void XmppClient::Private::WriteOutput(const char* bytes, size_t len) {
388 //#if !defined(NDEBUG)
389 client_->SignalLogOutput(bytes, static_cast<int>(len));
390 //#endif
391
392 socket_->Write(bytes, len);
393 // TODO: deal with error information
394 }
395
396 void XmppClient::Private::StartTls(const std::string& domain) {
397 #if defined(FEATURE_ENABLE_SSL)
398 socket_->StartTls(domain);
399 #endif
400 }
401
402 void XmppClient::Private::CloseConnection() {
403 socket_->Close();
404 }
405
406 void XmppClient::AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) {
407 d_->engine_->AddStanzaHandler(task, level);
408 }
409
410 void XmppClient::RemoveXmppTask(XmppTask* task) {
411 d_->engine_->RemoveStanzaHandler(task);
412 }
413
414 void XmppClient::EnsureClosed() {
415 if (!d_->signal_closed_) {
416 d_->signal_closed_ = true;
417 delivering_signal_ = true;
418 SignalStateChange(XmppEngine::STATE_CLOSED);
419 delivering_signal_ = false;
420 }
421 }
422
423 } // namespace buzz
OLDNEW
« no previous file with comments | « third_party/libjingle_xmpp/xmpp/xmppclient.h ('k') | third_party/libjingle_xmpp/xmpp/xmppclientsettings.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698