diff options
author | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-10 16:53:42 +0000 |
---|---|---|
committer | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-10 16:53:42 +0000 |
commit | ba62fbd428232eee1815d4b4d63fc65cb3ead566 (patch) | |
tree | 56d05f663fe81afc7c7f6c232d1f650994bbe8ed | |
parent | a538b1cdbd69c307ef672b5176c8ac9039981c41 (diff) | |
download | chromium_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
26 files changed, 533 insertions, 73 deletions
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index c352dce..2cf676e 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -278,6 +278,12 @@ void ProfileSyncService::InitSettings() { << " for test sync notification server."; } + notifier_options_.use_chrome_async_socket = + !command_line.HasSwitch(switches::kSyncDisableChromeAsyncSocket); + if (notifier_options_.use_chrome_async_socket) { + LOG(INFO) << "Using ChromeAsyncSocket"; + } + notifier_options_.try_ssltcp_first = command_line.HasSwitch(switches::kSyncUseSslTcp); if (notifier_options_.try_ssltcp_first) { diff --git a/chrome/browser/sync/tools/sync_listen_notifications.cc b/chrome/browser/sync/tools/sync_listen_notifications.cc index 5fdc9f9..0a7751d 100644 --- a/chrome/browser/sync/tools/sync_listen_notifications.cc +++ b/chrome/browser/sync/tools/sync_listen_notifications.cc @@ -21,6 +21,7 @@ #include "jingle/notifier/base/notification_method.h" #include "jingle/notifier/base/task_pump.h" #include "jingle/notifier/base/xmpp_client_socket_factory.h" +#include "jingle/notifier/communicator/xmpp_socket_adapter.h" #include "jingle/notifier/listener/listen_task.h" #include "jingle/notifier/listener/notification_constants.h" #include "jingle/notifier/listener/subscribe_task.h" @@ -29,6 +30,9 @@ #include "talk/base/cryptstring.h" #include "talk/base/logging.h" #include "talk/base/sigslot.h" +#include "talk/base/physicalsocketserver.h" +#include "talk/base/ssladapter.h" +#include "talk/base/thread.h" #include "talk/xmpp/jid.h" #include "talk/xmpp/xmppclient.h" #include "talk/xmpp/xmppclientsettings.h" @@ -41,6 +45,14 @@ namespace { +void PumpAuxiliaryLoops() { + talk_base::Thread* current_thread = + talk_base::ThreadManager::CurrentThread(); + current_thread->ProcessMessages(100); + MessageLoop::current()->PostTask( + FROM_HERE, NewRunnableFunction(&PumpAuxiliaryLoops)); +} + // Main class that listens for and handles messages from the XMPP // client. class XmppNotificationClient : public sigslot::has_slots<> { @@ -72,7 +84,8 @@ class XmppNotificationClient : public sigslot::has_slots<> { } // Connect with the given XMPP settings and run until disconnected. - void Run(const buzz::XmppClientSettings& xmpp_client_settings) { + void Run(const buzz::XmppClientSettings& xmpp_client_settings, + bool use_chrome_async_socket) { CHECK(!xmpp_client_); xmpp_client_settings_ = xmpp_client_settings; xmpp_client_ = new buzz::XmppClient(&task_pump_); @@ -88,11 +101,15 @@ class XmppNotificationClient : public sigslot::has_slots<> { bool use_fake_ssl_client_socket = (xmpp_client_settings.protocol() == cricket::PROTO_SSLTCP); buzz::AsyncSocket* buzz_async_socket = - new notifier::ChromeAsyncSocket( - new notifier::XmppClientSocketFactory( - net::ClientSocketFactory::GetDefaultFactory(), - use_fake_ssl_client_socket), - ssl_config, 4096, 64 * 1024, NULL); + use_chrome_async_socket ? + static_cast<buzz::AsyncSocket*>( + new notifier::ChromeAsyncSocket( + new notifier::XmppClientSocketFactory( + net::ClientSocketFactory::GetDefaultFactory(), + use_fake_ssl_client_socket), + ssl_config, 4096, 64 * 1024, NULL)) : + static_cast<buzz::AsyncSocket*>( + new notifier::XmppSocketAdapter(xmpp_client_settings_, false)); CHECK(buzz_async_socket); // Transfers ownership of buzz_async_socket. buzz::XmppReturnStatus connect_status = @@ -100,6 +117,10 @@ class XmppNotificationClient : public sigslot::has_slots<> { buzz_async_socket, NULL); CHECK_EQ(connect_status, buzz::XMPP_RETURN_OK); xmpp_client_->Start(); + if (!use_chrome_async_socket) { + MessageLoop::current()->PostTask( + FROM_HERE, NewRunnableFunction(&PumpAuxiliaryLoops)); + } MessageLoop::current()->Run(); DCHECK(!xmpp_client_); } @@ -322,6 +343,11 @@ int main(int argc, char* argv[]) { } xmpp_client_settings.set_server(addr); + // Set up message loops and socket servers. + talk_base::PhysicalSocketServer physical_socket_server; + talk_base::InitializeSSL(); + talk_base::Thread main_thread(&physical_socket_server); + talk_base::ThreadManager::SetCurrent(&main_thread); MessageLoopForIO message_loop; // Connect and listen. @@ -335,8 +361,11 @@ int main(int argc, char* argv[]) { } // TODO(akalin): Revert the move of all switches in this file into // chrome_switches.h. + bool use_chrome_async_socket = + command_line.HasSwitch("use-chrome-async-socket"); XmppNotificationClient xmpp_notification_client(delegate); - xmpp_notification_client.Run(xmpp_client_settings); + xmpp_notification_client.Run(xmpp_client_settings, + use_chrome_async_socket); return 0; } diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 9d38d74..4962663 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -988,6 +988,11 @@ const char kStartMaximized[] = "start-maximized"; // Control Sync XMPP client settings. const char kSyncAllowPlain[] = "allow-plain"; +// Disable the Chrome-socket-based buzz::AsyncSocket implementation +// for sync notifications, instead using libjingle sockets. +const char kSyncDisableChromeAsyncSocket[] = + "sync-disable-chrome-async-socket"; + // Control Sync XMPP client settings. const char kSyncDisableTls[] = "disable-tls"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index bcaacfe..dca0d15 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -279,6 +279,7 @@ extern const char kSimpleDataSource[]; extern const char kSingleProcess[]; extern const char kStartMaximized[]; extern const char kSyncAllowPlain[]; +extern const char kSyncDisableChromeAsyncSocket[]; extern const char kSyncDisableTls[]; extern const char kSyncEmail[]; extern const char kSyncerThreadTimedStop[]; 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/remoting/jingle_glue/ssl_adapter.cc b/jingle/notifier/base/ssl_adapter.cc index 68d350c..2111244 100644 --- a/remoting/jingle_glue/ssl_adapter.cc +++ b/jingle/notifier/base/ssl_adapter.cc @@ -2,26 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/jingle_glue/ssl_adapter.h" +#include "jingle/notifier/base/ssl_adapter.h" #if defined(OS_WIN) #include "talk/base/ssladapter.h" #else -#include "remoting/jingle_glue/ssl_socket_adapter.h" +#include "jingle/notifier/communicator/ssl_socket_adapter.h" #endif -namespace remoting { +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 - remoting::SSLSocketAdapter::Create(socket); + notifier::SSLSocketAdapter::Create(socket); #endif DCHECK(ssl_adapter); return ssl_adapter; } -} // namespace remoting +} // namespace notifier diff --git a/remoting/jingle_glue/ssl_adapter.h b/jingle/notifier/base/ssl_adapter.h index 56b03be..32517cd 100644 --- a/remoting/jingle_glue/ssl_adapter.h +++ b/jingle/notifier/base/ssl_adapter.h @@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_JINGLE_GLUE_SSL_ADAPTER_H_ -#define REMOTING_JINGLE_GLUE_SSL_ADAPTER_H_ +#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 remoting { +namespace notifier { // Wraps the given socket in a platform-dependent SSLAdapter // implementation. @@ -23,11 +23,11 @@ class SSLAdapterSocketFactory : public SocketFactory { public: virtual talk_base::SSLAdapter* CreateSSLAdapter( talk_base::AsyncSocket* socket) { - return ::remoting::CreateSSLAdapter(socket); + return ::notifier::CreateSSLAdapter(socket); } }; -} // namespace remoting +} // namespace notifier -#endif // REMOTING_JINGLE_GLUE_SSL_ADAPTER_H_ +#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/remoting/jingle_glue/ssl_socket_adapter.cc b/jingle/notifier/communicator/ssl_socket_adapter.cc index 3ea404b..cac3041 100644 --- a/remoting/jingle_glue/ssl_socket_adapter.cc +++ b/jingle/notifier/communicator/ssl_socket_adapter.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/jingle_glue/ssl_socket_adapter.h" +#include "jingle/notifier/communicator/ssl_socket_adapter.h" #include "base/compiler_specific.h" #include "base/message_loop.h" @@ -13,7 +13,7 @@ #include "net/socket/client_socket_factory.h" #include "net/url_request/url_request_context.h" -namespace remoting { +namespace notifier { namespace { @@ -383,4 +383,4 @@ void TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) { } } -} // namespace remoting +} // namespace notifier diff --git a/remoting/jingle_glue/ssl_socket_adapter.h b/jingle/notifier/communicator/ssl_socket_adapter.h index a22e2b7..cdbc94e 100644 --- a/remoting/jingle_glue/ssl_socket_adapter.h +++ b/jingle/notifier/communicator/ssl_socket_adapter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_JINGLE_GLUE_SSL_SOCKET_ADAPTER_H_ -#define REMOTING_JINGLE_GLUE_SSL_SOCKET_ADAPTER_H_ +#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" @@ -15,7 +15,7 @@ #include "talk/base/asyncsocket.h" #include "talk/base/ssladapter.h" -namespace remoting { +namespace notifier { class SSLSocketAdapter; @@ -81,7 +81,7 @@ class TransportSocket : public net::ClientSocket, public sigslot::has_slots<> { }; // This provides a talk_base::AsyncSocketAdapter interface around Chromium's -// net::SSLClientSocket class. This allows remoting to use Chromium's SSL +// net::SSLClientSocket class. This allows notifier to use Chromium's SSL // implementation instead of OpenSSL. class SSLSocketAdapter : public talk_base::SSLAdapter { public: @@ -140,6 +140,6 @@ class SSLSocketAdapter : public talk_base::SSLAdapter { DISALLOW_COPY_AND_ASSIGN(SSLSocketAdapter); }; -} // namespace remoting +} // namespace notifier -#endif // REMOTING_JINGLE_GLUE_SSL_SOCKET_ADAPTER_H_ +#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/remoting/jingle_glue/xmpp_socket_adapter.cc b/jingle/notifier/communicator/xmpp_socket_adapter.cc index 08f72aa..7d7a2e9 100644 --- a/remoting/jingle_glue/xmpp_socket_adapter.cc +++ b/jingle/notifier/communicator/xmpp_socket_adapter.cc @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/jingle_glue/xmpp_socket_adapter.h" +#include "jingle/notifier/communicator/xmpp_socket_adapter.h" #include <iomanip> #include <string> #include "base/logging.h" -#include "remoting/jingle_glue/ssl_adapter.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" @@ -18,7 +19,7 @@ #include "talk/base/thread.h" #include "talk/xmpp/xmppengine.h" -namespace remoting { +namespace notifier { XmppSocketAdapter::XmppSocketAdapter(const buzz::XmppClientSettings& xcs, bool allow_unverified_certs) @@ -110,7 +111,7 @@ bool XmppSocketAdapter::Connect(const talk_base::SocketAddress& addr) { } else { // Note: we are trying unknown proxies as HTTPS currently. proxy_socket = new talk_base::AsyncHttpsProxySocket(socket, - "chromoting", proxy_.address, proxy_.username, + GetUserAgentString(), proxy_.address, proxy_.username, proxy_.password); } if (!proxy_socket) { @@ -133,7 +134,7 @@ bool XmppSocketAdapter::Connect(const talk_base::SocketAddress& addr) { } #if defined(FEATURE_ENABLE_SSL) - talk_base::SSLAdapter* ssl_adapter = remoting::CreateSSLAdapter(socket); + talk_base::SSLAdapter* ssl_adapter = notifier::CreateSSLAdapter(socket); socket = ssl_adapter; // For our purposes the SSL adapter is the socket. #endif @@ -425,4 +426,4 @@ bool XmppSocketAdapter::HandleWritable() { return true; } -} // namespace remoting +} // namespace notifier diff --git a/remoting/jingle_glue/xmpp_socket_adapter.h b/jingle/notifier/communicator/xmpp_socket_adapter.h index d1a6f65..ff22a9c 100644 --- a/remoting/jingle_glue/xmpp_socket_adapter.h +++ b/jingle/notifier/communicator/xmpp_socket_adapter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_JINGLE_GLUE_XMPP_SOCKET_ADAPTER_H_ -#define REMOTING_JINGLE_GLUE_XMPP_SOCKET_ADAPTER_H_ +#ifndef JINGLE_NOTIFIER_COMMUNICATOR_XMPP_SOCKET_ADAPTER_H_ +#define JINGLE_NOTIFIER_COMMUNICATOR_XMPP_SOCKET_ADAPTER_H_ #include <string> @@ -18,7 +18,7 @@ #define WSA_NOT_ENOUGH_MEMORY ENOMEM #endif -namespace remoting { +namespace notifier { class XmppSocketAdapter : public buzz::AsyncSocket, public sigslot::has_slots<> { @@ -82,6 +82,6 @@ class XmppSocketAdapter : public buzz::AsyncSocket, DISALLOW_COPY_AND_ASSIGN(XmppSocketAdapter); }; -} // namespace remoting +} // namespace notifier -#endif // REMOTING_JINGLE_GLUE_XMPP_SOCKET_ADAPTER_H_ +#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); }; diff --git a/remoting/DEPS b/remoting/DEPS index 6bfe57b..4370b43 100644 --- a/remoting/DEPS +++ b/remoting/DEPS @@ -3,7 +3,6 @@ include_rules = [ "+gfx", "+google/protobuf", "+media/base", - "+net", "+jingle", diff --git a/remoting/jingle_glue/jingle_client.cc b/remoting/jingle_glue/jingle_client.cc index d3ca67e..01e607b 100644 --- a/remoting/jingle_glue/jingle_client.cc +++ b/remoting/jingle_glue/jingle_client.cc @@ -7,10 +7,10 @@ #include "base/logging.h" #include "base/message_loop.h" #include "jingle/notifier/communicator/gaia_token_pre_xmpp_auth.h" +#include "jingle/notifier/communicator/xmpp_socket_adapter.h" #include "remoting/jingle_glue/iq_request.h" #include "remoting/jingle_glue/jingle_thread.h" #include "remoting/jingle_glue/relay_port_allocator.h" -#include "remoting/jingle_glue/xmpp_socket_adapter.h" #include "third_party/libjingle/source/talk/base/asyncsocket.h" #include "third_party/libjingle/source/talk/base/ssladapter.h" #include "third_party/libjingle/source/talk/p2p/base/sessionmanager.h" @@ -94,7 +94,7 @@ void JingleClient::DoInitialize(const std::string& username, client_->SignalStateChange.connect( this, &JingleClient::OnConnectionStateChanged); - buzz::AsyncSocket* socket = new XmppSocketAdapter(settings, false); + buzz::AsyncSocket* socket = new notifier::XmppSocketAdapter(settings, false); client_->Connect(settings, "", socket, CreatePreXmppAuth(settings)); client_->Start(); diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index b0c52e2..71b81d0 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -316,12 +316,6 @@ 'jingle_glue/jingle_thread.h', 'jingle_glue/relay_port_allocator.cc', 'jingle_glue/relay_port_allocator.h', - 'jingle_glue/ssl_adapter.h', - 'jingle_glue/ssl_adapter.cc', - 'jingle_glue/ssl_socket_adapter.cc', - 'jingle_glue/ssl_socket_adapter.h', - 'jingle_glue/xmpp_socket_adapter.cc', - 'jingle_glue/xmpp_socket_adapter.h', ], }, # end of target 'chromoting_jingle_glue' |