summaryrefslogtreecommitdiffstats
path: root/jingle
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-10 16:53:42 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-10 16:53:42 +0000
commitba62fbd428232eee1815d4b4d63fc65cb3ead566 (patch)
tree56d05f663fe81afc7c7f6c232d1f650994bbe8ed /jingle
parenta538b1cdbd69c307ef672b5176c8ac9039981c41 (diff)
downloadchromium_src-ba62fbd428232eee1815d4b4d63fc65cb3ead566.zip
chromium_src-ba62fbd428232eee1815d4b4d63fc65cb3ead566.tar.gz
chromium_src-ba62fbd428232eee1815d4b4d63fc65cb3ead566.tar.bz2
Revert r59012 which started using Chrome sockets for sync.
This caused us to write to ChromeNetLog from the sync thread. ChromeNetLog is not thread safe, so this causes problems. BUG=55116,54146 TEST=Start up chrome. Does not repeatedly hit DCHECKs on ChromeNetLog::AddEntry(). Review URL: http://codereview.chromium.org/3358028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59104 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'jingle')
-rw-r--r--jingle/jingle.gyp11
-rw-r--r--jingle/notifier/base/notifier_options.h13
-rw-r--r--jingle/notifier/base/signal_thread_task.h96
-rw-r--r--jingle/notifier/base/ssl_adapter.cc27
-rw-r--r--jingle/notifier/base/ssl_adapter.h33
-rw-r--r--jingle/notifier/base/static_assert.h21
-rw-r--r--jingle/notifier/communicator/login.cc7
-rw-r--r--jingle/notifier/communicator/login.h2
-rw-r--r--jingle/notifier/communicator/product_info.cc15
-rw-r--r--jingle/notifier/communicator/product_info.h15
-rw-r--r--jingle/notifier/communicator/single_login_attempt.cc230
-rw-r--r--jingle/notifier/communicator/single_login_attempt.h11
-rw-r--r--jingle/notifier/communicator/ssl_socket_adapter.cc386
-rw-r--r--jingle/notifier/communicator/ssl_socket_adapter.h145
-rw-r--r--jingle/notifier/communicator/xmpp_connection_generator.cc2
-rw-r--r--jingle/notifier/communicator/xmpp_socket_adapter.cc429
-rw-r--r--jingle/notifier/communicator/xmpp_socket_adapter.h87
-rw-r--r--jingle/notifier/listener/mediator_thread_impl.cc46
-rw-r--r--jingle/notifier/listener/mediator_thread_impl.h8
19 files changed, 1558 insertions, 26 deletions
diff --git a/jingle/jingle.gyp b/jingle/jingle.gyp
index 79ee350..2f01fff 100644
--- a/jingle/jingle.gyp
+++ b/jingle/jingle.gyp
@@ -17,11 +17,15 @@
'sources': [
'notifier/base/chrome_async_socket.cc',
'notifier/base/chrome_async_socket.h',
+ 'notifier/base/signal_thread_task.h',
+ 'notifier/base/ssl_adapter.h',
+ 'notifier/base/ssl_adapter.cc',
'notifier/base/fake_ssl_client_socket.cc',
'notifier/base/fake_ssl_client_socket.h',
'notifier/base/notification_method.h',
'notifier/base/notification_method.cc',
'notifier/base/notifier_options.h',
+ 'notifier/base/static_assert.h',
'notifier/base/task_pump.cc',
'notifier/base/task_pump.h',
'notifier/base/xmpp_client_socket_factory.cc',
@@ -40,10 +44,16 @@
'notifier/communicator/login_failure.h',
'notifier/communicator/login_settings.cc',
'notifier/communicator/login_settings.h',
+ 'notifier/communicator/product_info.cc',
+ 'notifier/communicator/product_info.h',
'notifier/communicator/single_login_attempt.cc',
'notifier/communicator/single_login_attempt.h',
+ 'notifier/communicator/ssl_socket_adapter.cc',
+ 'notifier/communicator/ssl_socket_adapter.h',
'notifier/communicator/xmpp_connection_generator.cc',
'notifier/communicator/xmpp_connection_generator.h',
+ 'notifier/communicator/xmpp_socket_adapter.cc',
+ 'notifier/communicator/xmpp_socket_adapter.h',
'notifier/listener/listen_task.cc',
'notifier/listener/listen_task.h',
'notifier/listener/mediator_thread.h',
@@ -67,6 +77,7 @@
'defines' : [
'_CRT_SECURE_NO_WARNINGS',
'_USE_32BIT_TIME_T',
+ 'kXmppProductName="chromium-sync"',
],
'dependencies': [
'../base/base.gyp:base',
diff --git a/jingle/notifier/base/notifier_options.h b/jingle/notifier/base/notifier_options.h
index 289b7d8..32374cf 100644
--- a/jingle/notifier/base/notifier_options.h
+++ b/jingle/notifier/base/notifier_options.h
@@ -12,16 +12,23 @@ namespace notifier {
struct NotifierOptions {
NotifierOptions()
- : try_ssltcp_first(false),
+ : use_chrome_async_socket(true),
+ try_ssltcp_first(false),
notification_method(kDefaultNotificationMethod) {}
- NotifierOptions(const bool try_ssltcp_first,
+ NotifierOptions(const bool use_chrome_async_socket,
+ const bool try_ssltcp_first,
const net::HostPortPair& xmpp_host_port,
NotificationMethod notification_method)
- : try_ssltcp_first(try_ssltcp_first),
+ : use_chrome_async_socket(use_chrome_async_socket),
+ try_ssltcp_first(try_ssltcp_first),
xmpp_host_port(xmpp_host_port),
notification_method(notification_method) {}
+ // Indicates whether to use the chrome-socket-based buzz::AsyncSocket
+ // implementation for notifications.
+ bool use_chrome_async_socket;
+
// Indicates that the SSLTCP port (443) is to be tried before the the XMPP
// port (5222) during login.
bool try_ssltcp_first;
diff --git a/jingle/notifier/base/signal_thread_task.h b/jingle/notifier/base/signal_thread_task.h
new file mode 100644
index 0000000..8a6ff27
--- /dev/null
+++ b/jingle/notifier/base/signal_thread_task.h
@@ -0,0 +1,96 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef JINGLE_NOTIFIER_BASE_SIGNAL_THREAD_TASK_H_
+#define JINGLE_NOTIFIER_BASE_SIGNAL_THREAD_TASK_H_
+
+#include "base/logging.h"
+#include "talk/base/common.h"
+#include "talk/base/signalthread.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/task.h"
+
+namespace notifier {
+
+template<class T>
+class SignalThreadTask : public talk_base::Task,
+ public sigslot::has_slots<> {
+ public:
+ // Takes ownership of signal_thread.
+ SignalThreadTask(talk_base::Task* task_parent, T** signal_thread)
+ : talk_base::Task(task_parent),
+ signal_thread_(NULL),
+ finished_(false) {
+ SetSignalThread(signal_thread);
+ }
+
+ virtual ~SignalThreadTask() {
+ ClearSignalThread();
+ }
+
+ virtual void Stop() {
+ Task::Stop();
+ ClearSignalThread();
+ }
+
+ virtual int ProcessStart() {
+ DCHECK_EQ(GetState(), talk_base::Task::STATE_START);
+ signal_thread_->SignalWorkDone.connect(
+ this,
+ &SignalThreadTask<T>::OnWorkDone);
+ signal_thread_->Start();
+ return talk_base::Task::STATE_RESPONSE;
+ }
+
+ int ProcessResponse() {
+ if (!finished_) {
+ return talk_base::Task::STATE_BLOCKED;
+ }
+ SignalWorkDone(signal_thread_);
+ ClearSignalThread();
+ return talk_base::Task::STATE_DONE;
+ }
+
+ sigslot::signal1<T*> SignalWorkDone;
+
+ private:
+ // Takes ownership of signal_thread.
+ void SetSignalThread(T** signal_thread) {
+ DCHECK(!signal_thread_);
+ DCHECK(signal_thread);
+ DCHECK(*signal_thread);
+ // No one should be listening to the signal thread for work done.
+ // They should be using this class instead. Unfortunately, we
+ // can't verify this.
+
+ signal_thread_ = *signal_thread;
+
+ // Helps callers not to use signal thread after this point since this class
+ // has taken ownership (and avoid the error of doing
+ // signal_thread->Start()).
+ *signal_thread = NULL;
+ }
+
+ void OnWorkDone(talk_base::SignalThread* signal_thread) {
+ DCHECK_EQ(signal_thread, signal_thread_);
+ finished_ = true;
+ Wake();
+ }
+
+ void ClearSignalThread() {
+ if (signal_thread_) {
+ // Don't wait on the thread destruction, or we may deadlock.
+ signal_thread_->Destroy(false);
+ signal_thread_ = NULL;
+ }
+ }
+
+ T* signal_thread_;
+ bool finished_;
+ DISALLOW_COPY_AND_ASSIGN(SignalThreadTask);
+};
+
+} // namespace notifier
+
+#endif // JINGLE_NOTIFIER_BASE_SIGNAL_THREAD_TASK_H_
diff --git a/jingle/notifier/base/ssl_adapter.cc b/jingle/notifier/base/ssl_adapter.cc
new file mode 100644
index 0000000..2111244
--- /dev/null
+++ b/jingle/notifier/base/ssl_adapter.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "jingle/notifier/base/ssl_adapter.h"
+
+#if defined(OS_WIN)
+#include "talk/base/ssladapter.h"
+#else
+#include "jingle/notifier/communicator/ssl_socket_adapter.h"
+#endif
+
+namespace notifier {
+
+talk_base::SSLAdapter* CreateSSLAdapter(talk_base::AsyncSocket* socket) {
+ talk_base::SSLAdapter* ssl_adapter =
+#if defined(OS_WIN)
+ talk_base::SSLAdapter::Create(socket);
+#else
+ notifier::SSLSocketAdapter::Create(socket);
+#endif
+ DCHECK(ssl_adapter);
+ return ssl_adapter;
+}
+
+} // namespace notifier
+
diff --git a/jingle/notifier/base/ssl_adapter.h b/jingle/notifier/base/ssl_adapter.h
new file mode 100644
index 0000000..32517cd
--- /dev/null
+++ b/jingle/notifier/base/ssl_adapter.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef JINGLE_NOTIFIER_BASE_SSL_ADAPTER_H_
+#define JINGLE_NOTIFIER_BASE_SSL_ADAPTER_H_
+
+namespace talk_base {
+class AsyncSocket;
+class SSLAdapter;
+} // namespace talk_base
+
+namespace notifier {
+
+// Wraps the given socket in a platform-dependent SSLAdapter
+// implementation.
+talk_base::SSLAdapter* CreateSSLAdapter(talk_base::AsyncSocket* socket);
+
+// Utility template class that overrides CreateSSLAdapter() to use the
+// above function.
+template <class SocketFactory>
+class SSLAdapterSocketFactory : public SocketFactory {
+ public:
+ virtual talk_base::SSLAdapter* CreateSSLAdapter(
+ talk_base::AsyncSocket* socket) {
+ return ::notifier::CreateSSLAdapter(socket);
+ }
+};
+
+} // namespace notifier
+
+#endif // JINGLE_NOTIFIER_BASE_SSL_ADAPTER_H_
+
diff --git a/jingle/notifier/base/static_assert.h b/jingle/notifier/base/static_assert.h
new file mode 100644
index 0000000..58a8fe4
--- /dev/null
+++ b/jingle/notifier/base/static_assert.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef JINGLE_NOTIFIER_BASE_STATIC_ASSERT_H_
+#define JINGLE_NOTIFIER_BASE_STATIC_ASSERT_H_
+
+template<bool> struct STATIC_ASSERTION_FAILURE;
+
+template<> struct STATIC_ASSERTION_FAILURE<true> {
+ enum { value = 1 };
+};
+
+template<int> struct static_assert_test{};
+
+#define STATIC_ASSERT(B) \
+typedef static_assert_test<\
+ sizeof(STATIC_ASSERTION_FAILURE< (bool)( B ) >)>\
+ static_assert_typedef_ ## __LINE__
+
+#endif // JINGLE_NOTIFIER_BASE_STATIC_ASSERT_H_
diff --git a/jingle/notifier/communicator/login.cc b/jingle/notifier/communicator/login.cc
index cd0cbbf..041bc67 100644
--- a/jingle/notifier/communicator/login.cc
+++ b/jingle/notifier/communicator/login.cc
@@ -11,6 +11,7 @@
#include "base/time.h"
#include "jingle/notifier/communicator/connection_options.h"
#include "jingle/notifier/communicator/login_settings.h"
+#include "jingle/notifier/communicator/product_info.h"
#include "jingle/notifier/communicator/single_login_attempt.h"
#include "net/base/host_port_pair.h"
#include "talk/base/common.h"
@@ -31,6 +32,7 @@ namespace notifier {
static const int kRedirectTimeoutMinutes = 5;
Login::Login(talk_base::TaskParent* parent,
+ bool use_chrome_async_socket,
const buzz::XmppClientSettings& user_settings,
const ConnectionOptions& options,
std::string lang,
@@ -41,6 +43,7 @@ Login::Login(talk_base::TaskParent* parent,
bool try_ssltcp_first,
bool proxy_only)
: parent_(parent),
+ use_chrome_async_socket_(use_chrome_async_socket),
login_settings_(new LoginSettings(user_settings,
options,
lang,
@@ -80,7 +83,9 @@ void Login::StartConnection() {
LOG(INFO) << "Starting connection...";
single_attempt_ = new SingleLoginAttempt(parent_,
- login_settings_.get());
+ login_settings_.get(),
+ use_chrome_async_socket_,
+ true);
// Do the signaling hook-ups.
single_attempt_->SignalUnexpectedDisconnect.connect(
diff --git a/jingle/notifier/communicator/login.h b/jingle/notifier/communicator/login.h
index 27b2543..84e89a8 100644
--- a/jingle/notifier/communicator/login.h
+++ b/jingle/notifier/communicator/login.h
@@ -49,6 +49,7 @@ class Login : public net::NetworkChangeNotifier::Observer,
public:
// firewall may be NULL.
Login(talk_base::TaskParent* parent,
+ bool use_chrome_async_socket,
const buzz::XmppClientSettings& user_settings,
const ConnectionOptions& options,
std::string lang,
@@ -97,6 +98,7 @@ class Login : public net::NetworkChangeNotifier::Observer,
void DoReconnect();
talk_base::TaskParent* parent_;
+ bool use_chrome_async_socket_;
scoped_ptr<LoginSettings> login_settings_;
LoginConnectionState state_;
SingleLoginAttempt* single_attempt_;
diff --git a/jingle/notifier/communicator/product_info.cc b/jingle/notifier/communicator/product_info.cc
new file mode 100644
index 0000000..c1deafb
--- /dev/null
+++ b/jingle/notifier/communicator/product_info.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+namespace notifier {
+std::string GetUserAgentString() {
+ return kXmppProductName;
+}
+
+std::string GetProductSignature() {
+ return kXmppProductName;
+}
+} // namespace notifier
diff --git a/jingle/notifier/communicator/product_info.h b/jingle/notifier/communicator/product_info.h
new file mode 100644
index 0000000..9e8e5d0
--- /dev/null
+++ b/jingle/notifier/communicator/product_info.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef JINGLE_NOTIFIER_COMMUNICATOR_PRODUCT_INFO_H_
+#define JINGLE_NOTIFIER_COMMUNICATOR_PRODUCT_INFO_H_
+
+#include <string>
+
+namespace notifier {
+std::string GetUserAgentString();
+std::string GetProductSignature();
+} // namespace notifier
+
+#endif // JINGLE_NOTIFIER_COMMUNICATOR_PRODUCT_INFO_H_
diff --git a/jingle/notifier/communicator/single_login_attempt.cc b/jingle/notifier/communicator/single_login_attempt.cc
index 4db7758..ccdf0ce 100644
--- a/jingle/notifier/communicator/single_login_attempt.cc
+++ b/jingle/notifier/communicator/single_login_attempt.cc
@@ -18,9 +18,16 @@
#include "jingle/notifier/communicator/gaia_token_pre_xmpp_auth.h"
#include "jingle/notifier/communicator/login_failure.h"
#include "jingle/notifier/communicator/login_settings.h"
+#include "jingle/notifier/communicator/product_info.h"
#include "jingle/notifier/communicator/xmpp_connection_generator.h"
+#include "jingle/notifier/communicator/xmpp_socket_adapter.h"
#include "net/base/ssl_config_service.h"
#include "net/socket/client_socket_factory.h"
+#include "talk/base/asynchttprequest.h"
+#include "talk/base/firewallsocketserver.h"
+#include "talk/base/signalthread.h"
+#include "talk/base/taskrunner.h"
+#include "talk/base/win32socketinit.h"
#include "talk/xmllite/xmlelement.h"
#include "talk/xmpp/xmppclient.h"
#include "talk/xmpp/xmppclientsettings.h"
@@ -54,15 +61,23 @@ static void GetClientErrorInformation(
}
SingleLoginAttempt::SingleLoginAttempt(talk_base::TaskParent* parent,
- LoginSettings* login_settings)
+ LoginSettings* login_settings,
+ bool use_chrome_async_socket,
+ bool successful_connection)
: talk_base::Task(parent),
+ use_chrome_async_socket_(use_chrome_async_socket),
state_(buzz::XmppEngine::STATE_NONE),
code_(buzz::XmppEngine::ERROR_NONE),
subcode_(0),
need_authentication_(false),
certificate_expired_(false),
+ cookie_refreshed_(false),
+ successful_connection_(successful_connection),
login_settings_(login_settings),
client_(NULL) {
+#if defined(OS_WIN)
+ talk_base::EnsureWinsockInit();
+#endif
connection_generator_.reset(new XmppConnectionGenerator(
this,
login_settings_->host_resolver(),
@@ -139,7 +154,14 @@ void SingleLoginAttempt::OnAttemptedAllConnections(
LOG(INFO) << "Connection failed with error " << code_;
- SignalNeedAutoReconnect();
+ // We were connected and we had a problem.
+ if (successful_connection_) {
+ SignalNeedAutoReconnect();
+ // Expect to be deleted at this point.
+ return;
+ }
+
+ DiagnoseConnectionError();
}
void SingleLoginAttempt::UseNextConnection() {
@@ -203,24 +225,39 @@ void SingleLoginAttempt::OnCertificateExpired() {
buzz::AsyncSocket* SingleLoginAttempt::CreateSocket(
const buzz::XmppClientSettings& xcs) {
- bool use_fake_ssl_client_socket =
- (xcs.protocol() == cricket::PROTO_SSLTCP);
- net::ClientSocketFactory* const client_socket_factory =
- new XmppClientSocketFactory(
- net::ClientSocketFactory::GetDefaultFactory(),
- use_fake_ssl_client_socket);
- // The default SSLConfig is good enough for us for now.
- const net::SSLConfig ssl_config;
- // A read buffer of 64k ought to be sufficient.
- const size_t kReadBufSize = 64U * 1024U;
- // This number was taken from a similar number in
- // XmppSocketAdapter.
- const size_t kWriteBufSize = 64U * 1024U;
- // TODO(akalin): Use a real NetLog.
- net::NetLog* const net_log = NULL;
- return new ChromeAsyncSocket(
- client_socket_factory, ssl_config,
- kReadBufSize, kWriteBufSize, net_log);
+ if (use_chrome_async_socket_) {
+ bool use_fake_ssl_client_socket =
+ (xcs.protocol() == cricket::PROTO_SSLTCP);
+ net::ClientSocketFactory* const client_socket_factory =
+ new XmppClientSocketFactory(
+ net::ClientSocketFactory::GetDefaultFactory(),
+ use_fake_ssl_client_socket);
+ // The default SSLConfig is good enough for us for now.
+ const net::SSLConfig ssl_config;
+ // A read buffer of 64k ought to be sufficient.
+ const size_t kReadBufSize = 64U * 1024U;
+ // This number was taken from a similar number in
+ // XmppSocketAdapter.
+ const size_t kWriteBufSize = 64U * 1024U;
+ // TODO(akalin): Use a real NetLog.
+ net::NetLog* const net_log = NULL;
+ return new ChromeAsyncSocket(
+ client_socket_factory, ssl_config,
+ kReadBufSize, kWriteBufSize, net_log);
+ }
+ // TODO(akalin): Always use ChromeAsyncSocket and get rid of this
+ // code.
+ bool allow_unverified_certs =
+ login_settings_->connection_options().allow_unverified_certs();
+ XmppSocketAdapter* adapter = new XmppSocketAdapter(xcs,
+ allow_unverified_certs);
+ adapter->SignalAuthenticationError.connect(
+ this,
+ &SingleLoginAttempt::OnAuthenticationError);
+ if (login_settings_->firewall()) {
+ adapter->set_firewall(true);
+ }
+ return adapter;
}
buzz::PreXmppAuth* SingleLoginAttempt::CreatePreXmppAuth(
@@ -230,6 +267,147 @@ buzz::PreXmppAuth* SingleLoginAttempt::CreatePreXmppAuth(
jid.Str(), xcs.auth_cookie(), xcs.token_service());
}
+void SingleLoginAttempt::OnFreshAuthCookie(const std::string& auth_cookie) {
+ // Remember this is a fresh cookie.
+ cookie_refreshed_ = true;
+
+ // TODO(sync): do the cookie logic (part of which is in the #if 0 below).
+
+ // The following code is what PhoneWindow does for the equivalent method.
+#if 0
+ // Save cookie
+ AccountInfo current(account_history_.current());
+ current.set_auth_cookie(auth_cookie);
+ account_history_.set_current(current);
+
+ // Calc next time to refresh cookie, between 5 and 10 days. The cookie has
+ // 14 days of life; this gives at least 4 days of retries before the current
+ // cookie expires, maximizing the chance of having a valid cookie next time
+ // the connection servers go down.
+ FTULL now;
+
+ // NOTE: The following line is win32. Address this when implementing this
+ // code (doing "the cookie logic").
+ GetSystemTimeAsFileTime(&(now.ft));
+ ULONGLONG five_days = (ULONGLONG)10000 * 1000 * 60 * 60 * 24 * 5; // 5 days
+ ULONGLONG random = (ULONGLONG)10000 * // get to 100 ns units
+ ((rand() % (5 * 24 * 60)) * (60 * 1000) + // random min. in 5 day period
+ (rand() % 1000) * 60); // random 1/1000th of a minute
+ next_cookie_refresh_ = now.ull + five_days + random; // 5-10 days
+#endif
+}
+
+void SingleLoginAttempt::DiagnoseConnectionError() {
+ switch (code_) {
+ case buzz::XmppEngine::ERROR_MISSING_USERNAME:
+ case buzz::XmppEngine::ERROR_NETWORK_TIMEOUT:
+ case buzz::XmppEngine::ERROR_DOCUMENT_CLOSED:
+ case buzz::XmppEngine::ERROR_BIND:
+ case buzz::XmppEngine::ERROR_AUTH:
+ case buzz::XmppEngine::ERROR_TLS:
+ case buzz::XmppEngine::ERROR_UNAUTHORIZED:
+ case buzz::XmppEngine::ERROR_VERSION:
+ case buzz::XmppEngine::ERROR_STREAM:
+ case buzz::XmppEngine::ERROR_XML:
+ case buzz::XmppEngine::ERROR_NONE:
+ default: {
+ LoginFailure failure(LoginFailure::XMPP_ERROR, code_, subcode_);
+ SignalLoginFailure(failure);
+ return;
+ }
+
+ // The following errors require diagnosistics:
+ // * spurious close of connection
+ // * socket errors after auth
+ case buzz::XmppEngine::ERROR_CONNECTION_CLOSED:
+ case buzz::XmppEngine::ERROR_SOCKET:
+ break;
+ }
+
+ talk_base::AsyncHttpRequest *http_request =
+ new talk_base::AsyncHttpRequest(GetUserAgentString());
+ http_request->set_host("www.google.com");
+ http_request->set_port(80);
+ http_request->set_secure(false);
+ http_request->request().path = "/";
+ http_request->request().verb = talk_base::HV_GET;
+
+ talk_base::ProxyInfo proxy;
+ DCHECK(connection_generator_.get());
+ if (connection_generator_.get()) {
+ proxy = connection_generator_->proxy();
+ }
+ http_request->set_proxy(proxy);
+ http_request->set_firewall(login_settings_->firewall());
+
+ http_request->SignalWorkDone.connect(this,
+ &SingleLoginAttempt::OnHttpTestDone);
+ http_request->Start();
+ http_request->Release();
+}
+
+void SingleLoginAttempt::OnHttpTestDone(talk_base::SignalThread* thread) {
+ DCHECK(thread);
+
+ talk_base::AsyncHttpRequest* request =
+ static_cast<talk_base::AsyncHttpRequest*>(thread);
+
+ if (request->response().scode == 200) {
+ // We were able to do an HTTP GET of www.google.com:80
+
+ //
+ // The original error should be reported
+ //
+ LoginFailure failure(LoginFailure::XMPP_ERROR, code_, subcode_);
+ SignalLoginFailure(failure);
+ return;
+ }
+
+ // Otherwise lets transmute the error into ERROR_SOCKET, and put the subcode
+ // as an indicator of what we think the problem might be.
+
+#if 0
+ // TODO(sync): determine if notifier has an analogous situation.
+
+ //
+ // We weren't able to do an HTTP GET of www.google.com:80
+ //
+ GAutoupdater::Version version_logged_in(g_options.version_logged_in());
+ GAutoupdater::Version version_installed(GetProductVersion().c_str());
+ if (version_logged_in < version_installed) {
+ //
+ // Google Talk has been updated and can no longer connect to the Google
+ // Talk Service. Your firewall is probably not allowing the new version of
+ // Google Talk to connect to the internet. Please adjust your firewall
+ // settings to allow the new version of Google Talk to connect to the
+ // internet.
+ //
+ // We'll use the "error=1" to help figure this out for now.
+ //
+ LoginFailure failure(LoginFailure::XMPP_ERROR,
+ buzz::XmppEngine::ERROR_SOCKET,
+ 1);
+ SignalLoginFailure(failure);
+ return;
+ }
+#endif
+
+ //
+ // Any other checking we can add here?
+ //
+
+ //
+ // Google Talk is unable to use your internet connection. Either your network
+ // isn't configured or Google Talk is being blocked by a local firewall.
+ //
+ // We'll use the "error=0" to help figure this out for now
+ //
+ LoginFailure failure(LoginFailure::XMPP_ERROR,
+ buzz::XmppEngine::ERROR_SOCKET,
+ 0);
+ SignalLoginFailure(failure);
+}
+
void SingleLoginAttempt::OnClientStateChange(buzz::XmppEngine::State state) {
if (state_ == state)
return;
@@ -241,9 +419,11 @@ void SingleLoginAttempt::OnClientStateChange(buzz::XmppEngine::State state) {
case buzz::XmppEngine::STATE_NONE:
case buzz::XmppEngine::STATE_START:
case buzz::XmppEngine::STATE_OPENING:
- case buzz::XmppEngine::STATE_OPEN:
// Do nothing.
break;
+ case buzz::XmppEngine::STATE_OPEN:
+ successful_connection_ = true;
+ break;
case buzz::XmppEngine::STATE_CLOSED:
OnClientStateChangeClosed(previous_state);
break;
@@ -319,6 +499,14 @@ void SingleLoginAttempt::HandleConnectionError(
// Or internal server binding error -
// All these are temporary problems, so continue reconnecting.
+ // GaiaAuth signals this directly via SignalCertificateExpired, but
+ // SChannelAdapter propagates the error through SocketWindow as a socket
+ // error.
+ if (code_ == buzz::XmppEngine::ERROR_SOCKET &&
+ subcode_ == SEC_E_CERT_EXPIRED) {
+ certificate_expired_ = true;
+ }
+
login_settings_->modifiable_user_settings()->set_resource("");
// Look for stream::error server redirection stanza "see-other-host".
diff --git a/jingle/notifier/communicator/single_login_attempt.h b/jingle/notifier/communicator/single_login_attempt.h
index 1b9900c..8b4f93b 100644
--- a/jingle/notifier/communicator/single_login_attempt.h
+++ b/jingle/notifier/communicator/single_login_attempt.h
@@ -47,7 +47,9 @@ class XmppConnectionGenerator;
class SingleLoginAttempt : public talk_base::Task, public sigslot::has_slots<> {
public:
SingleLoginAttempt(talk_base::TaskParent* parent,
- LoginSettings* login_settings);
+ LoginSettings* login_settings,
+ bool use_chrome_async_socket,
+ bool successful_connection);
~SingleLoginAttempt();
virtual int ProcessStart();
void UseNextConnection();
@@ -105,18 +107,25 @@ class SingleLoginAttempt : public talk_base::Task, public sigslot::has_slots<> {
const buzz::XmlElement* stream_error);
void HandleConnectionPasswordError();
+ void DiagnoseConnectionError();
+ void OnHttpTestDone(talk_base::SignalThread* thread);
+
void OnAuthenticationError();
void OnCertificateExpired();
+ void OnFreshAuthCookie(const std::string& auth_cookie);
void OnClientStateChange(buzz::XmppEngine::State state);
void OnClientStateChangeClosed(buzz::XmppEngine::State previous_state);
void OnAttemptedAllConnections(bool successfully_resolved_dns,
int first_dns_error);
+ bool use_chrome_async_socket_;
buzz::XmppEngine::State state_;
buzz::XmppEngine::Error code_;
int subcode_;
bool need_authentication_;
bool certificate_expired_;
+ bool cookie_refreshed_;
+ bool successful_connection_;
LoginSettings* login_settings_;
buzz::XmppClient* client_;
scoped_ptr<XmppConnectionGenerator> connection_generator_;
diff --git a/jingle/notifier/communicator/ssl_socket_adapter.cc b/jingle/notifier/communicator/ssl_socket_adapter.cc
new file mode 100644
index 0000000..cac3041
--- /dev/null
+++ b/jingle/notifier/communicator/ssl_socket_adapter.cc
@@ -0,0 +1,386 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "jingle/notifier/communicator/ssl_socket_adapter.h"
+
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "net/base/address_list.h"
+#include "net/base/net_errors.h"
+#include "net/base/ssl_config_service.h"
+#include "net/base/sys_addrinfo.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/url_request/url_request_context.h"
+
+namespace notifier {
+
+namespace {
+
+// Convert values from <errno.h> to values from "net/base/net_errors.h"
+int MapPosixError(int err) {
+ // There are numerous posix error codes, but these are the ones we thus far
+ // find interesting.
+ switch (err) {
+ case EAGAIN:
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ return net::ERR_IO_PENDING;
+ case ENETDOWN:
+ return net::ERR_INTERNET_DISCONNECTED;
+ case ETIMEDOUT:
+ return net::ERR_TIMED_OUT;
+ case ECONNRESET:
+ case ENETRESET: // Related to keep-alive
+ return net::ERR_CONNECTION_RESET;
+ case ECONNABORTED:
+ return net::ERR_CONNECTION_ABORTED;
+ case ECONNREFUSED:
+ return net::ERR_CONNECTION_REFUSED;
+ case EHOSTUNREACH:
+ case ENETUNREACH:
+ return net::ERR_ADDRESS_UNREACHABLE;
+ case EADDRNOTAVAIL:
+ return net::ERR_ADDRESS_INVALID;
+ case 0:
+ return net::OK;
+ default:
+ LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
+ return net::ERR_FAILED;
+ }
+}
+
+} // namespace
+
+SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) {
+ return new SSLSocketAdapter(socket);
+}
+
+SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket)
+ : SSLAdapter(socket),
+ ignore_bad_cert_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ connected_callback_(this, &SSLSocketAdapter::OnConnected)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ read_callback_(this, &SSLSocketAdapter::OnRead)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ write_callback_(this, &SSLSocketAdapter::OnWrite)),
+ ssl_state_(SSLSTATE_NONE),
+ read_state_(IOSTATE_NONE),
+ write_state_(IOSTATE_NONE) {
+ transport_socket_ = new TransportSocket(socket, this);
+}
+
+SSLSocketAdapter::~SSLSocketAdapter() {
+}
+
+int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) {
+ DCHECK(!restartable);
+ hostname_ = hostname;
+
+ if (socket_->GetState() != Socket::CS_CONNECTED) {
+ ssl_state_ = SSLSTATE_WAIT;
+ return 0;
+ } else {
+ return BeginSSL();
+ }
+}
+
+int SSLSocketAdapter::BeginSSL() {
+ if (!MessageLoop::current()) {
+ // Certificate verification is done via the Chrome message loop.
+ // Without this check, if we don't have a chrome message loop the
+ // SSL connection just hangs silently.
+ LOG(DFATAL) << "Chrome message loop (needed by SSL certificate "
+ << "verification) does not exist";
+ return net::ERR_UNEXPECTED;
+ }
+
+ // SSLConfigService is not thread-safe, and the default values for SSLConfig
+ // are correct for us, so we don't use the config service to initialize this
+ // object.
+ net::SSLConfig ssl_config;
+ transport_socket_->set_addr(talk_base::SocketAddress(hostname_, 0));
+ ssl_socket_.reset(
+ net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
+ transport_socket_, hostname_.c_str(), ssl_config));
+
+ int result = ssl_socket_->Connect(&connected_callback_);
+
+ if (result == net::ERR_IO_PENDING || result == net::OK) {
+ return 0;
+ } else {
+ LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result);
+ return result;
+ }
+}
+
+int SSLSocketAdapter::Send(const void* buf, size_t len) {
+ if (ssl_state_ != SSLSTATE_CONNECTED) {
+ return AsyncSocketAdapter::Send(buf, len);
+ } else {
+ scoped_refptr<net::IOBuffer> transport_buf = new net::IOBuffer(len);
+ memcpy(transport_buf->data(), buf, len);
+
+ int result = ssl_socket_->Write(transport_buf, len, NULL);
+ if (result == net::ERR_IO_PENDING) {
+ SetError(EWOULDBLOCK);
+ }
+ transport_buf = NULL;
+ return result;
+ }
+}
+
+int SSLSocketAdapter::Recv(void* buf, size_t len) {
+ switch (ssl_state_) {
+ case SSLSTATE_NONE:
+ return AsyncSocketAdapter::Recv(buf, len);
+
+ case SSLSTATE_WAIT:
+ SetError(EWOULDBLOCK);
+ return -1;
+
+ case SSLSTATE_CONNECTED:
+ switch (read_state_) {
+ case IOSTATE_NONE: {
+ transport_buf_ = new net::IOBuffer(len);
+ int result = ssl_socket_->Read(transport_buf_, len, &read_callback_);
+ if (result >= 0) {
+ memcpy(buf, transport_buf_->data(), len);
+ }
+
+ if (result == net::ERR_IO_PENDING) {
+ read_state_ = IOSTATE_PENDING;
+ SetError(EWOULDBLOCK);
+ } else {
+ if (result < 0) {
+ SetError(result);
+ LOG(INFO) << "Socket error " << result;
+ }
+ transport_buf_ = NULL;
+ }
+ return result;
+ }
+ case IOSTATE_PENDING:
+ SetError(EWOULDBLOCK);
+ return -1;
+
+ case IOSTATE_COMPLETE:
+ memcpy(buf, transport_buf_->data(), len);
+ transport_buf_ = NULL;
+ read_state_ = IOSTATE_NONE;
+ return data_transferred_;
+ }
+ }
+
+ NOTREACHED();
+ return -1;
+}
+
+void SSLSocketAdapter::OnConnected(int result) {
+ if (result == net::OK) {
+ ssl_state_ = SSLSTATE_CONNECTED;
+ OnConnectEvent(this);
+ } else {
+ LOG(WARNING) << "OnConnected failed with error " << result;
+ }
+}
+
+void SSLSocketAdapter::OnRead(int result) {
+ DCHECK(read_state_ == IOSTATE_PENDING);
+ read_state_ = IOSTATE_COMPLETE;
+ data_transferred_ = result;
+ AsyncSocketAdapter::OnReadEvent(this);
+}
+
+void SSLSocketAdapter::OnWrite(int result) {
+ DCHECK(write_state_ == IOSTATE_PENDING);
+ write_state_ = IOSTATE_COMPLETE;
+ data_transferred_ = result;
+ AsyncSocketAdapter::OnWriteEvent(this);
+}
+
+void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) {
+ if (ssl_state_ != SSLSTATE_WAIT) {
+ AsyncSocketAdapter::OnConnectEvent(socket);
+ } else {
+ ssl_state_ = SSLSTATE_NONE;
+ int result = BeginSSL();
+ if (0 != result) {
+ // TODO(zork): Handle this case gracefully.
+ LOG(WARNING) << "BeginSSL() failed with " << result;
+ }
+ }
+}
+
+TransportSocket::TransportSocket(talk_base::AsyncSocket* socket,
+ SSLSocketAdapter *ssl_adapter)
+ : read_callback_(NULL),
+ write_callback_(NULL),
+ read_buffer_len_(0),
+ write_buffer_len_(0),
+ socket_(socket),
+ was_used_to_convey_data_(false) {
+ socket_->SignalReadEvent.connect(this, &TransportSocket::OnReadEvent);
+ socket_->SignalWriteEvent.connect(this, &TransportSocket::OnWriteEvent);
+}
+
+TransportSocket::~TransportSocket() {
+}
+
+int TransportSocket::Connect(net::CompletionCallback* callback) {
+ // Connect is never called by SSLClientSocket, instead SSLSocketAdapter
+ // calls Connect() on socket_ directly.
+ NOTREACHED();
+ return false;
+}
+
+void TransportSocket::Disconnect() {
+ socket_->Close();
+}
+
+bool TransportSocket::IsConnected() const {
+ return (socket_->GetState() == talk_base::Socket::CS_CONNECTED);
+}
+
+bool TransportSocket::IsConnectedAndIdle() const {
+ // Not implemented.
+ NOTREACHED();
+ return false;
+}
+
+int TransportSocket::GetPeerAddress(net::AddressList* address) const {
+ talk_base::SocketAddress socket_address = socket_->GetRemoteAddress();
+
+ // libjingle supports only IPv4 addresses.
+ sockaddr_in ipv4addr;
+ socket_address.ToSockAddr(&ipv4addr);
+
+ struct addrinfo ai;
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = ipv4addr.sin_family;
+ ai.ai_socktype = SOCK_STREAM;
+ ai.ai_protocol = IPPROTO_TCP;
+ ai.ai_addr = reinterpret_cast<struct sockaddr*>(&ipv4addr);
+ ai.ai_addrlen = sizeof(ipv4addr);
+
+ address->Copy(&ai, false);
+ return net::OK;
+}
+
+void TransportSocket::SetSubresourceSpeculation() {
+ NOTREACHED();
+}
+
+void TransportSocket::SetOmniboxSpeculation() {
+ NOTREACHED();
+}
+
+bool TransportSocket::WasEverUsed() const {
+ // We don't use this in ClientSocketPools, so this should never be used.
+ NOTREACHED();
+ return was_used_to_convey_data_;
+}
+
+int TransportSocket::Read(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback) {
+ DCHECK(buf);
+ DCHECK(!read_callback_);
+ DCHECK(!read_buffer_.get());
+ int result = socket_->Recv(buf->data(), buf_len);
+ if (result < 0) {
+ result = MapPosixError(socket_->GetError());
+ if (result == net::ERR_IO_PENDING) {
+ read_callback_ = callback;
+ read_buffer_ = buf;
+ read_buffer_len_ = buf_len;
+ }
+ }
+ if (result != net::ERR_IO_PENDING)
+ was_used_to_convey_data_ = true;
+ return result;
+}
+
+int TransportSocket::Write(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback) {
+ DCHECK(buf);
+ DCHECK(!write_callback_);
+ DCHECK(!write_buffer_.get());
+ int result = socket_->Send(buf->data(), buf_len);
+ if (result < 0) {
+ result = MapPosixError(socket_->GetError());
+ if (result == net::ERR_IO_PENDING) {
+ write_callback_ = callback;
+ write_buffer_ = buf;
+ write_buffer_len_ = buf_len;
+ }
+ }
+ if (result != net::ERR_IO_PENDING)
+ was_used_to_convey_data_ = true;
+ return result;
+}
+
+bool TransportSocket::SetReceiveBufferSize(int32 size) {
+ // Not implemented.
+ return false;
+}
+
+bool TransportSocket::SetSendBufferSize(int32 size) {
+ // Not implemented.
+ return false;
+}
+
+void TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) {
+ if (read_callback_) {
+ DCHECK(read_buffer_.get());
+ net::CompletionCallback* callback = read_callback_;
+ scoped_refptr<net::IOBuffer> buffer = read_buffer_;
+ int buffer_len = read_buffer_len_;
+
+ read_callback_ = NULL;
+ read_buffer_ = NULL;
+ read_buffer_len_ = 0;
+
+ int result = socket_->Recv(buffer->data(), buffer_len);
+ if (result < 0) {
+ result = MapPosixError(socket_->GetError());
+ if (result == net::ERR_IO_PENDING) {
+ read_callback_ = callback;
+ read_buffer_ = buffer;
+ read_buffer_len_ = buffer_len;
+ return;
+ }
+ }
+ was_used_to_convey_data_ = true;
+ callback->RunWithParams(Tuple1<int>(result));
+ }
+}
+
+void TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) {
+ if (write_callback_) {
+ DCHECK(write_buffer_.get());
+ net::CompletionCallback* callback = write_callback_;
+ scoped_refptr<net::IOBuffer> buffer = write_buffer_;
+ int buffer_len = write_buffer_len_;
+
+ write_callback_ = NULL;
+ write_buffer_ = NULL;
+ write_buffer_len_ = 0;
+
+ int result = socket_->Send(buffer->data(), buffer_len);
+ if (result < 0) {
+ result = MapPosixError(socket_->GetError());
+ if (result == net::ERR_IO_PENDING) {
+ write_callback_ = callback;
+ write_buffer_ = buffer;
+ write_buffer_len_ = buffer_len;
+ return;
+ }
+ }
+ was_used_to_convey_data_ = true;
+ callback->RunWithParams(Tuple1<int>(result));
+ }
+}
+
+} // namespace notifier
diff --git a/jingle/notifier/communicator/ssl_socket_adapter.h b/jingle/notifier/communicator/ssl_socket_adapter.h
new file mode 100644
index 0000000..cdbc94e
--- /dev/null
+++ b/jingle/notifier/communicator/ssl_socket_adapter.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef JINGLE_NOTIFIER_COMMUNICATOR_SSL_SOCKET_ADAPTER_H_
+#define JINGLE_NOTIFIER_COMMUNICATOR_SSL_SOCKET_ADAPTER_H_
+
+#include "base/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/socket/client_socket.h"
+#include "net/socket/ssl_client_socket.h"
+#include "talk/base/asyncsocket.h"
+#include "talk/base/ssladapter.h"
+
+namespace notifier {
+
+class SSLSocketAdapter;
+
+// TODO(sergeyu): Write unittests for this code!
+
+// This class provides a wrapper to libjingle's talk_base::AsyncSocket that
+// implements Chromium's net::ClientSocket interface. It's used by
+// SSLSocketAdapter to enable Chromium's SSL implementation to work over
+// libjingle's socket class.
+class TransportSocket : public net::ClientSocket, public sigslot::has_slots<> {
+ public:
+ TransportSocket(talk_base::AsyncSocket* socket,
+ SSLSocketAdapter *ssl_adapter);
+ ~TransportSocket();
+
+ void set_addr(const talk_base::SocketAddress& addr) {
+ addr_ = addr;
+ }
+
+ // net::ClientSocket implementation
+
+ virtual int Connect(net::CompletionCallback* callback);
+ virtual void Disconnect();
+ virtual bool IsConnected() const;
+ virtual bool IsConnectedAndIdle() const;
+ virtual int GetPeerAddress(net::AddressList* address) const;
+ virtual const net::BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
+
+ // net::Socket implementation
+
+ virtual int Read(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback);
+ virtual int Write(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback);
+ virtual bool SetReceiveBufferSize(int32 size);
+ virtual bool SetSendBufferSize(int32 size);
+
+ private:
+ friend class SSLSocketAdapter;
+
+ void OnReadEvent(talk_base::AsyncSocket* socket);
+ void OnWriteEvent(talk_base::AsyncSocket* socket);
+
+ net::CompletionCallback* read_callback_;
+ net::CompletionCallback* write_callback_;
+
+ scoped_refptr<net::IOBuffer> read_buffer_;
+ int read_buffer_len_;
+ scoped_refptr<net::IOBuffer> write_buffer_;
+ int write_buffer_len_;
+
+ net::BoundNetLog net_log_;
+
+ talk_base::AsyncSocket *socket_;
+ talk_base::SocketAddress addr_;
+
+ bool was_used_to_convey_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransportSocket);
+};
+
+// This provides a talk_base::AsyncSocketAdapter interface around Chromium's
+// net::SSLClientSocket class. This allows notifier to use Chromium's SSL
+// implementation instead of OpenSSL.
+class SSLSocketAdapter : public talk_base::SSLAdapter {
+ public:
+ explicit SSLSocketAdapter(talk_base::AsyncSocket* socket);
+ ~SSLSocketAdapter();
+
+ // StartSSL returns 0 if successful, or non-zero on failure.
+ // If StartSSL is called while the socket is closed or connecting, the SSL
+ // negotiation will begin as soon as the socket connects.
+ //
+ // restartable is not implemented, and must be set to false.
+ virtual int StartSSL(const char* hostname, bool restartable);
+
+ // Create the default SSL adapter for this platform.
+ static SSLSocketAdapter* Create(AsyncSocket* socket);
+
+ virtual int Send(const void* pv, size_t cb);
+ virtual int Recv(void* pv, size_t cb);
+
+ private:
+ friend class TransportSocket;
+
+ enum SSLState {
+ SSLSTATE_NONE,
+ SSLSTATE_WAIT,
+ SSLSTATE_CONNECTED,
+ };
+
+ enum IOState {
+ IOSTATE_NONE,
+ IOSTATE_PENDING,
+ IOSTATE_COMPLETE,
+ };
+
+ void OnConnected(int result);
+ void OnRead(int result);
+ void OnWrite(int result);
+
+ virtual void OnConnectEvent(talk_base::AsyncSocket* socket);
+
+ int BeginSSL();
+
+ bool ignore_bad_cert_;
+ std::string hostname_;
+ TransportSocket* transport_socket_;
+ scoped_ptr<net::SSLClientSocket> ssl_socket_;
+ net::CompletionCallbackImpl<SSLSocketAdapter> connected_callback_;
+ net::CompletionCallbackImpl<SSLSocketAdapter> read_callback_;
+ net::CompletionCallbackImpl<SSLSocketAdapter> write_callback_;
+ SSLState ssl_state_;
+ IOState read_state_;
+ IOState write_state_;
+ scoped_refptr<net::IOBuffer> transport_buf_;
+ int data_transferred_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLSocketAdapter);
+};
+
+} // namespace notifier
+
+#endif // JINGLE_NOTIFIER_COMMUNICATOR_SSL_SOCKET_ADAPTER_H_
diff --git a/jingle/notifier/communicator/xmpp_connection_generator.cc b/jingle/notifier/communicator/xmpp_connection_generator.cc
index 25b131c..ad551d2 100644
--- a/jingle/notifier/communicator/xmpp_connection_generator.cc
+++ b/jingle/notifier/communicator/xmpp_connection_generator.cc
@@ -23,8 +23,10 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "jingle/notifier/base/signal_thread_task.h"
#include "jingle/notifier/communicator/connection_options.h"
#include "jingle/notifier/communicator/connection_settings.h"
+#include "jingle/notifier/communicator/product_info.h"
#include "net/base/net_errors.h"
#include "net/base/sys_addrinfo.h"
#include "talk/base/httpcommon-inl.h"
diff --git a/jingle/notifier/communicator/xmpp_socket_adapter.cc b/jingle/notifier/communicator/xmpp_socket_adapter.cc
new file mode 100644
index 0000000..7d7a2e9
--- /dev/null
+++ b/jingle/notifier/communicator/xmpp_socket_adapter.cc
@@ -0,0 +1,429 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "jingle/notifier/communicator/xmpp_socket_adapter.h"
+
+#include <iomanip>
+#include <string>
+
+#include "base/logging.h"
+#include "jingle/notifier/base/ssl_adapter.h"
+#include "jingle/notifier/communicator/product_info.h"
+#include "talk/base/byteorder.h"
+#include "talk/base/common.h"
+#include "talk/base/firewallsocketserver.h"
+#include "talk/base/logging.h"
+#include "talk/base/socketadapters.h"
+#include "talk/base/ssladapter.h"
+#include "talk/base/thread.h"
+#include "talk/xmpp/xmppengine.h"
+
+namespace notifier {
+
+XmppSocketAdapter::XmppSocketAdapter(const buzz::XmppClientSettings& xcs,
+ bool allow_unverified_certs)
+ : state_(STATE_CLOSED),
+ error_(ERROR_NONE),
+ wsa_error_(0),
+ socket_(NULL),
+ protocol_(xcs.protocol()),
+ firewall_(false),
+ write_buffer_(NULL),
+ write_buffer_length_(0),
+ write_buffer_capacity_(0),
+ allow_unverified_certs_(allow_unverified_certs) {
+ proxy_.type = xcs.proxy();
+ proxy_.address.SetIP(xcs.proxy_host());
+ proxy_.address.SetPort(xcs.proxy_port());
+ proxy_.username = xcs.proxy_user();
+ proxy_.password = xcs.proxy_pass();
+}
+
+XmppSocketAdapter::~XmppSocketAdapter() {
+ FreeState();
+
+ // Clean up any previous socket - cannot delete socket on close because close
+ // happens during the child socket's stack callback.
+ if (socket_) {
+ delete socket_;
+ socket_ = NULL;
+ }
+}
+
+bool XmppSocketAdapter::FreeState() {
+ int code = 0;
+
+ // Clean up the socket.
+ if (socket_ && !(state_ == STATE_CLOSED || state_ == STATE_CLOSING)) {
+ code = socket_->Close();
+ }
+
+ delete[] write_buffer_;
+ write_buffer_ = NULL;
+ write_buffer_length_ = 0;
+ write_buffer_capacity_ = 0;
+
+ if (code) {
+ SetWSAError(code);
+ return false;
+ }
+ return true;
+}
+
+bool XmppSocketAdapter::Connect(const talk_base::SocketAddress& addr) {
+ if (state_ != STATE_CLOSED) {
+ SetError(ERROR_WRONGSTATE);
+ return false;
+ }
+
+ LOG(INFO) << "XmppSocketAdapter::Connect(" << addr.ToString() << ")";
+
+ // Clean up any previous socket - cannot delete socket on close because close
+ // happens during the child socket's stack callback.
+ if (socket_) {
+ delete socket_;
+ socket_ = NULL;
+ }
+
+ talk_base::AsyncSocket* socket =
+ talk_base::Thread::Current()->socketserver()->CreateAsyncSocket(
+ SOCK_STREAM);
+ if (!socket) {
+ SetWSAError(WSA_NOT_ENOUGH_MEMORY);
+ return false;
+ }
+
+ if (firewall_) {
+ // TODO(sync): Change this to make WSAAsyncSockets support current thread
+ // socket server.
+ talk_base::FirewallSocketServer* fw =
+ static_cast<talk_base::FirewallSocketServer*>(
+ talk_base::Thread::Current()->socketserver());
+ socket = fw->WrapSocket(socket, SOCK_STREAM);
+ }
+
+ if (proxy_.type) {
+ talk_base::AsyncSocket* proxy_socket = 0;
+ if (proxy_.type == talk_base::PROXY_SOCKS5) {
+ proxy_socket = new talk_base::AsyncSocksProxySocket(
+ socket, proxy_.address, proxy_.username, proxy_.password);
+ } else {
+ // Note: we are trying unknown proxies as HTTPS currently.
+ proxy_socket = new talk_base::AsyncHttpsProxySocket(socket,
+ GetUserAgentString(), proxy_.address, proxy_.username,
+ proxy_.password);
+ }
+ if (!proxy_socket) {
+ SetWSAError(WSA_NOT_ENOUGH_MEMORY);
+ delete socket;
+ return false;
+ }
+ socket = proxy_socket; // For our purposes the proxy is now the socket.
+ }
+
+ if (protocol_ == cricket::PROTO_SSLTCP) {
+ talk_base::AsyncSocket *fake_ssl_socket =
+ new talk_base::AsyncSSLSocket(socket);
+ if (!fake_ssl_socket) {
+ SetWSAError(WSA_NOT_ENOUGH_MEMORY);
+ delete socket;
+ return false;
+ }
+ socket = fake_ssl_socket; // For our purposes the SSL socket is the socket.
+ }
+
+#if defined(FEATURE_ENABLE_SSL)
+ talk_base::SSLAdapter* ssl_adapter = notifier::CreateSSLAdapter(socket);
+ socket = ssl_adapter; // For our purposes the SSL adapter is the socket.
+#endif
+
+ socket->SignalReadEvent.connect(this, &XmppSocketAdapter::OnReadEvent);
+ socket->SignalWriteEvent.connect(this, &XmppSocketAdapter::OnWriteEvent);
+ socket->SignalConnectEvent.connect(this, &XmppSocketAdapter::OnConnectEvent);
+ socket->SignalCloseEvent.connect(this, &XmppSocketAdapter::OnCloseEvent);
+
+ // The linux implementation of socket::Connect returns an error when the
+ // connect didn't complete yet. This can be distinguished from a failure
+ // because socket::IsBlocking is true. Perhaps, the linux implementation
+ // should be made to behave like the windows version which doesn't do this,
+ // but it seems to be a pattern with these methods that they return an error
+ // if the operation didn't complete in a sync fashion and one has to check
+ // IsBlocking to tell if was a "real" error.
+ if (socket->Connect(addr) == SOCKET_ERROR && !socket->IsBlocking()) {
+ SetWSAError(socket->GetError());
+ delete socket;
+ return false;
+ }
+
+ socket_ = socket;
+ state_ = STATE_CONNECTING;
+ return true;
+}
+
+bool XmppSocketAdapter::Read(char* data, size_t len, size_t* len_read) {
+ if (len_read)
+ *len_read = 0;
+
+ if (state_ <= STATE_CLOSING) {
+ SetError(ERROR_WRONGSTATE);
+ return false;
+ }
+
+ DCHECK(socket_);
+
+ if (IsOpen()) {
+ int result = socket_->Recv(data, len);
+ if (result < 0) {
+ if (!socket_->IsBlocking()) {
+ SetWSAError(socket_->GetError());
+ return false;
+ }
+
+ result = 0;
+ }
+
+ if (len_read)
+ *len_read = result;
+ }
+
+ return true;
+}
+
+bool XmppSocketAdapter::Write(const char* data, size_t len) {
+ if (state_ <= STATE_CLOSING) {
+ // There may be data in a buffer that gets lost. Too bad!
+ SetError(ERROR_WRONGSTATE);
+ return false;
+ }
+
+ DCHECK(socket_);
+
+ size_t sent = 0;
+
+ // Try an immediate write when there is no buffer and we aren't in SSL mode
+ // or opening the connection.
+ if (write_buffer_length_ == 0 && IsOpen()) {
+ int result = socket_->Send(data, len);
+ if (result < 0) {
+ if (!socket_->IsBlocking()) {
+ SetWSAError(socket_->GetError());
+ return false;
+ }
+ result = 0;
+ }
+
+ sent = static_cast<size_t>(result);
+ }
+
+ // Buffer what we didn't send.
+ if (sent < len) {
+ QueueWriteData(data + sent, len - sent);
+ }
+
+ // Service the socket right away to push the written data out in SSL mode.
+ return HandleWritable();
+}
+
+bool XmppSocketAdapter::Close() {
+ if (state_ == STATE_CLOSING) {
+ return false; // Avoid recursion, but not unexpected.
+ }
+ if (state_ == STATE_CLOSED) {
+ // In theory should not be trying to re-InternalClose.
+ SetError(ERROR_WRONGSTATE);
+ return false;
+ }
+
+ // TODO(sync): deal with flushing close (flush, don't do reads, clean ssl).
+
+ // If we've gotten to the point where we really do have a socket underneath
+ // then close it. It should call us back to tell us it is closed, and
+ // NotifyClose will be called. We indicate "closing" state so that we
+ // do not recusively try to keep closing the socket.
+ if (socket_) {
+ state_ = STATE_CLOSING;
+ socket_->Close();
+ }
+
+ // If we didn't get the callback, then we better make sure we signal
+ // closed.
+ if (state_ != STATE_CLOSED) {
+ // The socket was closed manually, not directly due to error.
+ if (error_ != ERROR_NONE) {
+ LOG(INFO) << "XmppSocketAdapter::Close - previous Error: " << error_
+ << " WSAError: " << wsa_error_;
+ error_ = ERROR_NONE;
+ wsa_error_ = 0;
+ }
+ NotifyClose();
+ }
+ return true;
+}
+
+void XmppSocketAdapter::NotifyClose() {
+ if (state_ == STATE_CLOSED) {
+ SetError(ERROR_WRONGSTATE);
+ } else {
+ LOG(INFO) << "XmppSocketAdapter::NotifyClose - Error: " << error_
+ << " WSAError: " << wsa_error_;
+ state_ = STATE_CLOSED;
+ SignalClosed();
+ FreeState();
+ }
+}
+
+void XmppSocketAdapter::OnConnectEvent(talk_base::AsyncSocket *socket) {
+ if (state_ == STATE_CONNECTING) {
+ state_ = STATE_OPEN;
+ LOG(INFO) << "XmppSocketAdapter::OnConnectEvent - STATE_OPEN";
+ SignalConnected();
+#if defined(FEATURE_ENABLE_SSL)
+ } else if (state_ == STATE_TLS_CONNECTING) {
+ state_ = STATE_TLS_OPEN;
+ LOG(INFO) << "XmppSocketAdapter::OnConnectEvent - STATE_TLS_OPEN";
+ SignalSSLConnected();
+ if (write_buffer_length_ > 0) {
+ HandleWritable();
+ }
+#endif // defined(FEATURE_ENABLE_SSL)
+ } else {
+ LOG(DFATAL) << "unexpected XmppSocketAdapter::OnConnectEvent state: "
+ << state_;
+ }
+}
+
+void XmppSocketAdapter::OnReadEvent(talk_base::AsyncSocket *socket) {
+ HandleReadable();
+}
+
+void XmppSocketAdapter::OnWriteEvent(talk_base::AsyncSocket *socket) {
+ HandleWritable();
+}
+
+void XmppSocketAdapter::OnCloseEvent(talk_base::AsyncSocket *socket,
+ int error) {
+ LOG(INFO) << "XmppSocketAdapter::OnCloseEvent(" << error << ")";
+ SetWSAError(error);
+ if (error == SOCKET_EACCES) {
+ SignalAuthenticationError(); // Proxy needs authentication.
+ }
+ NotifyClose();
+}
+
+#if defined(FEATURE_ENABLE_SSL)
+bool XmppSocketAdapter::StartTls(const std::string& verify_host_name) {
+ if (state_ != STATE_OPEN) {
+ SetError(ERROR_WRONGSTATE);
+ return false;
+ }
+
+ state_ = STATE_TLS_CONNECTING;
+
+ DCHECK_EQ(write_buffer_length_, 0U);
+
+ talk_base::SSLAdapter* ssl_adapter =
+ static_cast<talk_base::SSLAdapter*>(socket_);
+
+ if (allow_unverified_certs_) {
+ ssl_adapter->set_ignore_bad_cert(true);
+ }
+
+ if (ssl_adapter->StartSSL(verify_host_name.c_str(), false) != 0) {
+ state_ = STATE_OPEN;
+ SetError(ERROR_SSL);
+ return false;
+ }
+
+ return true;
+}
+#endif // defined(FEATURE_ENABLE_SSL)
+
+void XmppSocketAdapter::QueueWriteData(const char* data, size_t len) {
+ // Expand buffer if needed.
+ if (write_buffer_length_ + len > write_buffer_capacity_) {
+ size_t new_capacity = 1024;
+ while (new_capacity < write_buffer_length_ + len) {
+ new_capacity = new_capacity * 2;
+ }
+ char* new_buffer = new char[new_capacity];
+ DCHECK_LE(write_buffer_length_, 64000U);
+ memcpy(new_buffer, write_buffer_, write_buffer_length_);
+ delete[] write_buffer_;
+ write_buffer_ = new_buffer;
+ write_buffer_capacity_ = new_capacity;
+ }
+
+ // Copy data into the end of buffer.
+ memcpy(write_buffer_ + write_buffer_length_, data, len);
+ write_buffer_length_ += len;
+}
+
+void XmppSocketAdapter::FlushWriteQueue(Error* error, int* wsa_error) {
+ DCHECK(error);
+ DCHECK(wsa_error);
+
+ size_t flushed = 0;
+ while (flushed < write_buffer_length_) {
+ int sent = socket_->Send(write_buffer_ + flushed,
+ static_cast<int>(write_buffer_length_ - flushed));
+ if (sent < 0) {
+ if (!socket_->IsBlocking()) {
+ *error = ERROR_WINSOCK;
+ *wsa_error = socket_->GetError();
+ }
+ break;
+ }
+ flushed += static_cast<size_t>(sent);
+ }
+
+ // Remove flushed memory.
+ write_buffer_length_ -= flushed;
+ memmove(write_buffer_, write_buffer_ + flushed, write_buffer_length_);
+
+ // When everything is flushed, deallocate the buffer if it's gotten big.
+ if (write_buffer_length_ == 0) {
+ if (write_buffer_capacity_ > 8192) {
+ delete[] write_buffer_;
+ write_buffer_ = NULL;
+ write_buffer_capacity_ = 0;
+ }
+ }
+}
+
+void XmppSocketAdapter::SetError(Error error) {
+ if (error_ == ERROR_NONE) {
+ error_ = error;
+ }
+}
+
+void XmppSocketAdapter::SetWSAError(int error) {
+ if (error_ == ERROR_NONE && error != 0) {
+ error_ = ERROR_WINSOCK;
+ wsa_error_ = error;
+ }
+}
+
+bool XmppSocketAdapter::HandleReadable() {
+ if (!IsOpen())
+ return false;
+
+ SignalRead();
+ return true;
+}
+
+bool XmppSocketAdapter::HandleWritable() {
+ if (!IsOpen())
+ return false;
+
+ Error error = ERROR_NONE;
+ int wsa_error = 0;
+ FlushWriteQueue(&error, &wsa_error);
+ if (error != ERROR_NONE) {
+ Close();
+ return false;
+ }
+ return true;
+}
+
+} // namespace notifier
diff --git a/jingle/notifier/communicator/xmpp_socket_adapter.h b/jingle/notifier/communicator/xmpp_socket_adapter.h
new file mode 100644
index 0000000..ff22a9c
--- /dev/null
+++ b/jingle/notifier/communicator/xmpp_socket_adapter.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef JINGLE_NOTIFIER_COMMUNICATOR_XMPP_SOCKET_ADAPTER_H_
+#define JINGLE_NOTIFIER_COMMUNICATOR_XMPP_SOCKET_ADAPTER_H_
+
+#include <string>
+
+#include "talk/base/asyncsocket.h"
+#include "talk/xmpp/asyncsocket.h"
+#include "talk/xmpp/xmppclientsettings.h"
+#include "talk/xmpp/xmppengine.h"
+
+#ifndef _WIN32
+// Additional errors used by us from Win32 headers.
+#define SEC_E_CERT_EXPIRED static_cast<int>(0x80090328L)
+#define WSA_NOT_ENOUGH_MEMORY ENOMEM
+#endif
+
+namespace notifier {
+
+class XmppSocketAdapter : public buzz::AsyncSocket,
+ public sigslot::has_slots<> {
+ public:
+ XmppSocketAdapter(const buzz::XmppClientSettings& xcs,
+ bool allow_unverified_certs);
+ virtual ~XmppSocketAdapter();
+
+ virtual State state() { return state_; }
+ virtual Error error() { return error_; }
+ virtual int GetError() { return wsa_error_; }
+
+ void set_firewall(bool firewall) { firewall_ = firewall; }
+
+ virtual bool Connect(const talk_base::SocketAddress& addr);
+ virtual bool Read(char* data, size_t len, size_t* len_read);
+ virtual bool Write(const char* data, size_t len);
+ virtual bool Close();
+
+#if defined(FEATURE_ENABLE_SSL)
+ bool StartTls(const std::string& domainname);
+ bool IsOpen() const { return state_ == STATE_OPEN
+ || state_ == STATE_TLS_OPEN; }
+#else
+ bool IsOpen() const { return state_ == STATE_OPEN; }
+#endif
+
+ sigslot::signal0<> SignalAuthenticationError;
+
+ private:
+ // Return false if the socket is closed.
+ bool HandleReadable();
+ bool HandleWritable();
+
+ State state_;
+ Error error_;
+ int wsa_error_;
+
+ talk_base::AsyncSocket* socket_;
+ cricket::ProtocolType protocol_;
+ talk_base::ProxyInfo proxy_;
+ bool firewall_;
+ char* write_buffer_;
+ size_t write_buffer_length_;
+ size_t write_buffer_capacity_;
+ bool allow_unverified_certs_;
+
+ bool FreeState();
+ void NotifyClose();
+
+ void OnReadEvent(talk_base::AsyncSocket* socket);
+ void OnWriteEvent(talk_base::AsyncSocket* socket);
+ void OnConnectEvent(talk_base::AsyncSocket* socket);
+ void OnCloseEvent(talk_base::AsyncSocket* socket, int error);
+
+ void QueueWriteData(const char* data, size_t len);
+ void FlushWriteQueue(Error* error, int* wsa_error);
+
+ void SetError(Error error);
+ void SetWSAError(int error);
+ DISALLOW_COPY_AND_ASSIGN(XmppSocketAdapter);
+};
+
+} // namespace notifier
+
+#endif // JINGLE_NOTIFIER_COMMUNICATOR_XMPP_SOCKET_ADAPTER_H_
diff --git a/jingle/notifier/listener/mediator_thread_impl.cc b/jingle/notifier/listener/mediator_thread_impl.cc
index 918b49b..02d48fb1 100644
--- a/jingle/notifier/listener/mediator_thread_impl.cc
+++ b/jingle/notifier/listener/mediator_thread_impl.cc
@@ -16,6 +16,8 @@
#include "jingle/notifier/listener/subscribe_task.h"
#include "net/base/host_port_pair.h"
#include "net/base/host_resolver.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/thread.h"
#include "talk/xmpp/xmppclient.h"
#include "talk/xmpp/xmppclientsettings.h"
@@ -49,6 +51,44 @@ void MediatorThreadImpl::Start() {
// TODO(akalin): Make this function return a bool and remove this
// CHECK().
CHECK(worker_thread_.StartWithOptions(options));
+ if (!notifier_options_.use_chrome_async_socket) {
+ worker_message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &MediatorThreadImpl::StartLibjingleThread));
+ }
+}
+
+void MediatorThreadImpl::StartLibjingleThread() {
+ DCHECK_EQ(MessageLoop::current(), worker_message_loop());
+ DCHECK(!notifier_options_.use_chrome_async_socket);
+ socket_server_.reset(new talk_base::PhysicalSocketServer());
+ libjingle_thread_.reset(new talk_base::Thread());
+ talk_base::ThreadManager::SetCurrent(libjingle_thread_.get());
+ worker_message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &MediatorThreadImpl::PumpLibjingleLoop));
+}
+
+void MediatorThreadImpl::StopLibjingleThread() {
+ DCHECK_EQ(MessageLoop::current(), worker_message_loop());
+ DCHECK(!notifier_options_.use_chrome_async_socket);
+ talk_base::ThreadManager::SetCurrent(NULL);
+ libjingle_thread_.reset();
+ socket_server_.reset();
+}
+
+void MediatorThreadImpl::PumpLibjingleLoop() {
+ DCHECK_EQ(MessageLoop::current(), worker_message_loop());
+ DCHECK(!notifier_options_.use_chrome_async_socket);
+ // Pump the libjingle message loop 100ms at a time.
+ if (!libjingle_thread_.get()) {
+ // StopLibjingleThread() was called.
+ return;
+ }
+ libjingle_thread_->ProcessMessages(100);
+ worker_message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &MediatorThreadImpl::PumpLibjingleLoop));
}
void MediatorThreadImpl::Login(const buzz::XmppClientSettings& settings) {
@@ -63,6 +103,11 @@ void MediatorThreadImpl::Logout() {
worker_message_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &MediatorThreadImpl::DoDisconnect));
+ if (!notifier_options_.use_chrome_async_socket) {
+ worker_message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &MediatorThreadImpl::StopLibjingleThread));
+ }
// TODO(akalin): Decomp this into a separate stop method.
worker_thread_.Stop();
// Process any messages the worker thread may be posted on our
@@ -160,6 +205,7 @@ void MediatorThreadImpl::DoLogin(
// Language is not used in the stanza so we default to |en|.
std::string lang = "en";
login_.reset(new notifier::Login(pump_.get(),
+ notifier_options_.use_chrome_async_socket,
settings,
options,
lang,
diff --git a/jingle/notifier/listener/mediator_thread_impl.h b/jingle/notifier/listener/mediator_thread_impl.h
index 342079f..755731e 100644
--- a/jingle/notifier/listener/mediator_thread_impl.h
+++ b/jingle/notifier/listener/mediator_thread_impl.h
@@ -93,6 +93,10 @@ class MediatorThreadImpl
MessageLoop* parent_message_loop_;
private:
+ void StartLibjingleThread();
+ void PumpLibjingleLoop();
+ void StopLibjingleThread();
+
// Called from within the thread on internal events.
void DoLogin(const buzz::XmppClientSettings& settings);
void DoDisconnect();
@@ -133,6 +137,10 @@ class MediatorThreadImpl
scoped_ptr<notifier::TaskPump> pump_;
scoped_ptr<notifier::Login> login_;
+ // Used only when |use_chrome_async_socket_| is false.
+ scoped_ptr<talk_base::SocketServer> socket_server_;
+ scoped_ptr<talk_base::Thread> libjingle_thread_;
+
DISALLOW_COPY_AND_ASSIGN(MediatorThreadImpl);
};