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

Unified Diff: chrome/browser/sync/engine/auth_watcher.cc

Issue 246098: Sync: Remove pthreads from auth_watcher. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/sync/engine/auth_watcher.h ('k') | chrome/browser/sync/engine/auth_watcher_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/sync/engine/auth_watcher.cc
===================================================================
--- chrome/browser/sync/engine/auth_watcher.cc (revision 28272)
+++ chrome/browser/sync/engine/auth_watcher.cc (working copy)
@@ -11,12 +11,10 @@
#include "chrome/browser/sync/engine/net/gaia_authenticator.h"
#include "chrome/browser/sync/engine/net/server_connection_manager.h"
#include "chrome/browser/sync/notifier/listener/talk_mediator.h"
-#include "chrome/browser/sync/protocol/service_constants.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/util/character_set_converters.h"
#include "chrome/browser/sync/util/event_sys-inl.h"
-#include "chrome/browser/sync/util/pthread_helpers.h"
#include "chrome/browser/sync/util/user_settings.h"
// How authentication happens:
@@ -57,9 +55,14 @@
status_(NOT_AUTHENTICATED),
user_settings_(user_settings),
talk_mediator_(talk_mediator),
- thread_handle_valid_(false),
- authenticating_now_(false),
+ auth_backend_thread_("SyncEngine_AuthWatcherThread"),
current_attempt_trigger_(AuthWatcherEvent::USER_INITIATED) {
+
+ if (!auth_backend_thread_.Start())
+ NOTREACHED() << "Couldn't start SyncEngine_AuthWatcherThread";
+
+ gaia_->set_message_loop(message_loop());
+
connmgr_hookup_.reset(
NewEventListenerHookup(scm->channel(), this,
&AuthWatcher::HandleServerConnectionEvent));
@@ -67,12 +70,8 @@
channel_.reset(new Channel(done));
}
-void* AuthWatcher::AuthenticationThreadStartRoutine(void* arg) {
- ThreadParams* args = reinterpret_cast<ThreadParams*>(arg);
- return args->self->AuthenticationThreadMain(args);
-}
-
-bool AuthWatcher::ProcessGaiaAuthSuccess() {
+void AuthWatcher::PersistCredentials() {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
GaiaAuthenticator::AuthResults results = gaia_->results();
// We just successfully signed in again, let's clear out any residual cached
@@ -92,49 +91,20 @@
SYNC_SERVICE_NAME,
gaia_->auth_token());
}
-
- return AuthenticateWithToken(results.email, gaia_->auth_token());
}
-bool AuthWatcher::GetAuthTokenForService(const string& service_name,
- string* service_token) {
- string user_name;
+const char kAuthWatcher[] = "AuthWatcher";
- // We special case this one by trying to return it from memory first. We
- // do this because the user may not have checked "Remember me" and so we
- // may not have persisted the sync service token beyond the initial
- // login.
- if (SYNC_SERVICE_NAME == service_name && !sync_service_token_.empty()) {
- *service_token = sync_service_token_;
- return true;
- }
-
- if (user_settings_->GetLastUserAndServiceToken(service_name, &user_name,
- service_token)) {
- // The casing gets preserved in some places and not in others it seems,
- // at least I have observed different casings persisted to different DB
- // tables.
- if (!base::strcasecmp(user_name.c_str(),
- user_settings_->email().c_str())) {
- return true;
- } else {
- LOG(ERROR) << "ERROR: We seem to have saved credentials for someone "
- << " other than the current user.";
- return false;
- }
- }
-
- return false;
+void AuthWatcher::AuthenticateWithToken(const std::string& gaia_email,
+ const std::string& auth_token) {
+ message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &AuthWatcher::DoAuthenticateWithToken, gaia_email, auth_token));
}
-const char kAuthWatcher[] = "AuthWatcher";
+void AuthWatcher::DoAuthenticateWithToken(const std::string& gaia_email,
+ const std::string& auth_token) {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
-bool AuthWatcher::AuthenticateWithToken(const string& gaia_email,
- const string& auth_token) {
- // Store a copy of the sync service token in memory.
- sync_service_token_ = auth_token;
- scm_->set_auth_token(sync_service_token_);
-
Authenticator auth(scm_, user_settings_);
Authenticator::AuthenticationResult result =
auth.AuthenticateToken(auth_token);
@@ -158,11 +128,12 @@
// Set the authentication token for notifications
talk_mediator_->SetAuthToken(email, auth_token);
+ scm_->set_auth_token(auth_token);
if (!was_authenticated)
LoadDirectoryListAndOpen(share_name);
NotifyAuthSucceeded(email);
- return true;
+ return;
}
case Authenticator::BAD_AUTH_TOKEN:
event.what_happened = AuthWatcherEvent::SERVICE_AUTH_FAILED;
@@ -176,19 +147,19 @@
break;
default:
LOG(FATAL) << "Illegal return from AuthenticateToken";
- return true; // keep the compiler happy
+ return;
}
// Always fall back to local authentication.
if (was_authenticated || AuthenticateLocally(email)) {
if (AuthWatcherEvent::SERVICE_CONNECTION_FAILED == event.what_happened)
- return true;
+ return;
}
- CHECK(event.what_happened != AuthWatcherEvent::ILLEGAL_VALUE);
+ DCHECK_NE(event.what_happened, AuthWatcherEvent::ILLEGAL_VALUE);
NotifyListeners(&event);
- return true;
}
bool AuthWatcher::AuthenticateLocally(string email) {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
user_settings_->GetEmailForSignin(&email);
if (file_util::PathExists(FilePath(dirman_->GetSyncDataDatabasePath()))) {
gaia_->SetUsername(email);
@@ -205,12 +176,14 @@
}
bool AuthWatcher::AuthenticateLocally(string email, const string& password) {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
user_settings_->GetEmailForSignin(&email);
return user_settings_->VerifyAgainstStoredHash(email, password)
&& AuthenticateLocally(email);
}
void AuthWatcher::ProcessGaiaAuthFailure() {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
GaiaAuthenticator::AuthResults results = gaia_->results();
if (LOCALLY_AUTHENTICATED == status_) {
return; // nothing todo
@@ -234,77 +207,44 @@
NotifyListeners(&myevent);
}
-void* AuthWatcher::AuthenticationThreadMain(ThreadParams* args) {
- NameCurrentThreadForDebugging("SyncEngine_AuthWatcherThread");
- // TODO(timsteele): Remove this; this is temporary to satisfy code that
- // compares MessageLoop pointers until AuthWatcher uses a base::Thread.
- // We allocate a message_loop from the AuthWatcherThread so that
- // GaiaAuth and EventChannel get a valid opaque pointer to the current
- // message loop used for comparison. It gets stored in TLS as the 'current'
- // loop for this thread.
- MessageLoop message_loop;
- {
- // This short lock ensures our launching function (StartNewAuthAttempt) is
- // done.
- MutexLock lock(&mutex_);
- current_attempt_trigger_ = args->trigger;
- }
- SaveCredentials save = args->persist_creds_to_disk ?
+void AuthWatcher::DoAuthenticate(const AuthRequest& request) {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
+
+ AuthWatcherEvent event = { AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START };
+ NotifyListeners(&event);
+
+ current_attempt_trigger_ = request.trigger;
+
+ SaveCredentials save = request.persist_creds_to_disk ?
PERSIST_TO_DISK : SAVE_IN_MEMORY_ONLY;
- int attempt = 0;
SignIn const signin = user_settings_->
- RecallSigninType(args->email, GMAIL_SIGNIN);
+ RecallSigninType(request.email, GMAIL_SIGNIN);
- gaia_->set_message_loop(&message_loop);
-
- if (!args->password.empty()) {
- // TODO(timsteele): Split this mess up into functions.
- while (true) {
- bool authenticated;
- if (!args->captcha_token.empty() && !args->captcha_value.empty()) {
- authenticated = gaia_->Authenticate(args->email, args->password,
- save, args->captcha_token,
- args->captcha_value, signin);
- } else {
- authenticated = gaia_->Authenticate(args->email, args->password,
- save, signin);
- }
- if (authenticated) {
- if (!ProcessGaiaAuthSuccess()) {
- if (3 != ++attempt) {
- continue;
- }
- AuthWatcherEvent event =
- { AuthWatcherEvent::SERVICE_CONNECTION_FAILED, 0 };
- NotifyListeners(&event);
- }
- } else {
- ProcessGaiaAuthFailure();
- }
- break; // We are done trying to authenticate.
+ if (!request.password.empty()) {
+ bool authenticated = false;
+ if (!request.captcha_token.empty() && !request.captcha_value.empty()) {
+ authenticated = gaia_->Authenticate(request.email, request.password,
+ save, request.captcha_token,
+ request.captcha_value, signin);
+ } else {
+ authenticated = gaia_->Authenticate(request.email, request.password,
+ save, signin);
}
- } else if (!args->auth_token.empty()) {
- AuthenticateWithToken(args->email, args->auth_token);
+ if (authenticated) {
+ PersistCredentials();
+ DoAuthenticateWithToken(gaia_->email(), gaia_->auth_token());
+ } else {
+ ProcessGaiaAuthFailure();
+ }
+ } else if (!request.auth_token.empty()) {
+ DoAuthenticateWithToken(request.email, request.auth_token);
} else {
- LOG(ERROR) << "Attempt to authenticate with no credentials.";
+ LOG(ERROR) << "Attempt to authenticate with no credentials.";
}
-
- // We're done trying to authenticate. Set state and terminate the thread.
- {
- MutexLock lock(&mutex_);
- authenticating_now_ = false;
- }
- // TODO(timsteele): Remove this; nothing ever gets posted to this loop.
- gaia_->set_message_loop(NULL);
- delete args;
- return 0;
}
-void AuthWatcher::Reset() {
- status_ = NOT_AUTHENTICATED;
-}
-
void AuthWatcher::NotifyAuthSucceeded(const string& email) {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
LOG(INFO) << "NotifyAuthSucceeded";
AuthWatcherEvent event = { AuthWatcherEvent::AUTH_SUCCEEDED };
event.user_email = email;
@@ -312,76 +252,40 @@
NotifyListeners(&event);
}
-bool AuthWatcher::StartNewAuthAttempt(const string& email,
- const string& password, const string& auth_token,
- const string& captcha_token, const string& captcha_value,
- bool persist_creds_to_disk,
- AuthWatcherEvent::AuthenticationTrigger trigger) {
- AuthWatcherEvent event = { AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START };
- NotifyListeners(&event);
- MutexLock lock(&mutex_);
- if (authenticating_now_)
- return false;
- if (thread_handle_valid_) {
- int join_return = pthread_join(thread_, 0);
- if (0 != join_return)
- LOG(ERROR) << "pthread_join failed returning " << join_return;
- }
- string mail = email;
- if (email.find('@') == string::npos) {
- mail.push_back('@');
- // TODO(chron): Should this be done only at the UI level?
- mail.append(DEFAULT_SIGNIN_DOMAIN);
- }
- ThreadParams* args = new ThreadParams;
- args->self = this;
- args->email = mail;
- args->password = password;
- args->auth_token = auth_token;
- args->captcha_token = captcha_token;
- args->captcha_value = captcha_value;
- args->persist_creds_to_disk = persist_creds_to_disk;
- args->trigger = trigger;
- if (0 != pthread_create(&thread_, NULL, AuthenticationThreadStartRoutine,
- args)) {
- LOG(ERROR) << "Failed to create auth thread.";
- return false;
- }
- authenticating_now_ = true;
- thread_handle_valid_ = true;
- return true;
-}
-
-void AuthWatcher::WaitForAuthThreadFinish() {
- {
- MutexLock lock(&mutex_);
- if (!thread_handle_valid_)
- return;
- }
- pthread_join(thread_, 0);
-}
-
void AuthWatcher::HandleServerConnectionEvent(
const ServerConnectionEvent& event) {
+ message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &AuthWatcher::DoHandleServerConnectionEvent, event,
+ scm_->auth_token()));
+}
+
+void AuthWatcher::DoHandleServerConnectionEvent(
+ const ServerConnectionEvent& event,
+ const std::string& auth_token_snapshot) {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
if (event.server_reachable &&
- !authenticating_now_ &&
+ // If the auth_token at the time of the event differs from the current
+ // one, we have authenticated since then and don't need to re-try.
+ (auth_token_snapshot == gaia_->auth_token()) &&
(event.connection_code == HttpResponse::SYNC_AUTH_ERROR ||
- status_ == LOCALLY_AUTHENTICATED)) {
+ status_ == LOCALLY_AUTHENTICATED)) {
// We're either online or just got reconnected and want to try to
// authenticate. If we've got a saved token this should just work. If not
// the auth failure should trigger UI indications that we're not logged in.
// METRIC: If we get a SYNC_AUTH_ERROR, our token expired.
GaiaAuthenticator::AuthResults authresults = gaia_->results();
- if (!StartNewAuthAttempt(authresults.email, authresults.password,
- authresults.auth_token, "", "",
- PERSIST_TO_DISK == authresults.credentials_saved,
- AuthWatcherEvent::EXPIRED_CREDENTIALS))
- LOG(INFO) << "Couldn't start a new auth attempt.";
+ AuthRequest request = { authresults.email, authresults.password,
+ authresults.auth_token, std::string(),
+ std::string(),
+ PERSIST_TO_DISK == authresults.credentials_saved,
+ AuthWatcherEvent::EXPIRED_CREDENTIALS };
+ DoAuthenticate(request);
}
}
bool AuthWatcher::LoadDirectoryListAndOpen(const PathString& login) {
+ DCHECK_EQ(MessageLoop::current(), message_loop());
LOG(INFO) << "LoadDirectoryListAndOpen(" << login << ")";
bool initial_sync_ended = false;
@@ -395,33 +299,30 @@
}
AuthWatcher::~AuthWatcher() {
- WaitForAuthThreadFinish();
+ auth_backend_thread_.Stop();
+ // The gaia authenticator takes a const MessageLoop* because it only uses it
+ // to ensure all methods are invoked on the given loop. Once our thread has
+ // stopped, the current message loop will be NULL, and no methods should be
+ // invoked on |gaia_| after this point. We could set it to NULL, but
+ // abstaining allows for even more sanity checking that nothing is invoked on
+ // it from now on.
}
void AuthWatcher::Authenticate(const string& email, const string& password,
const string& captcha_token, const string& captcha_value,
bool persist_creds_to_disk) {
LOG(INFO) << "AuthWatcher::Authenticate called";
- WaitForAuthThreadFinish();
- // We CHECK here because WaitForAuthThreadFinish should ensure there's no
- // ongoing auth attempt.
string empty;
- CHECK(StartNewAuthAttempt(email, password, empty, captcha_token,
- captcha_value, persist_creds_to_disk,
- AuthWatcherEvent::USER_INITIATED));
+ AuthRequest request = { FormatAsEmailAddress(email), password, empty,
+ captcha_token, captcha_value, persist_creds_to_disk,
+ AuthWatcherEvent::USER_INITIATED };
+ message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &AuthWatcher::DoAuthenticate, request));
}
-void AuthWatcher::Logout() {
- scm_->ResetAuthStatus();
- Reset();
- WaitForAuthThreadFinish();
- ClearAuthenticationData();
-}
-
void AuthWatcher::ClearAuthenticationData() {
- sync_service_token_.clear();
- scm_->set_auth_token(sync_service_token());
+ scm_->set_auth_token(std::string());
user_settings_->ClearAllServiceTokens();
}
« no previous file with comments | « chrome/browser/sync/engine/auth_watcher.h ('k') | chrome/browser/sync/engine/auth_watcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698