Index: chrome/browser/sync/engine/net/server_connection_manager.cc |
diff --git a/chrome/browser/sync/engine/net/server_connection_manager.cc b/chrome/browser/sync/engine/net/server_connection_manager.cc |
index 9f0b5518e63878e8c9b34964d66da28b0d4d3e5e..bceb18713f1e6e192b78d169917e8f2cdb6e9edd 100644 |
--- a/chrome/browser/sync/engine/net/server_connection_manager.cc |
+++ b/chrome/browser/sync/engine/net/server_connection_manager.cc |
@@ -58,7 +58,14 @@ const char* HttpResponse::GetServerConnectionCodeString( |
#undef ENUM_CASE |
-bool ServerConnectionManager::Post::ReadBufferResponse( |
+ServerConnectionManager::Connection::Connection( |
+ ServerConnectionManager* scm) : scm_(scm) { |
+} |
+ |
+ServerConnectionManager::Connection::~Connection() { |
+} |
+ |
+bool ServerConnectionManager::Connection::ReadBufferResponse( |
string* buffer_out, |
HttpResponse* response, |
bool require_response) { |
@@ -79,7 +86,7 @@ bool ServerConnectionManager::Post::ReadBufferResponse( |
return true; |
} |
-bool ServerConnectionManager::Post::ReadDownloadResponse( |
+bool ServerConnectionManager::Connection::ReadDownloadResponse( |
HttpResponse* response, |
string* buffer_out) { |
const int64 bytes_read = ReadResponse(buffer_out, |
@@ -94,6 +101,21 @@ bool ServerConnectionManager::Post::ReadDownloadResponse( |
return true; |
} |
+ServerConnectionManager::ScopedConnectionHelper::ScopedConnectionHelper( |
+ ServerConnectionManager* manager, Connection* connection) |
+ : manager_(manager), connection_(connection) {} |
+ |
+ServerConnectionManager::ScopedConnectionHelper::~ScopedConnectionHelper() { |
+ if (connection_.get()) |
+ manager_->OnConnectionDestroyed(connection_.get()); |
+ connection_.reset(); |
+} |
+ |
+ServerConnectionManager::Connection* |
+ServerConnectionManager::ScopedConnectionHelper::get() { |
+ return connection_.get(); |
+} |
+ |
namespace { |
string StripTrailingSlash(const string& s) { |
@@ -108,7 +130,7 @@ string StripTrailingSlash(const string& s) { |
} // namespace |
// TODO(chron): Use a GURL instead of string concatenation. |
-string ServerConnectionManager::Post::MakeConnectionURL( |
+string ServerConnectionManager::Connection::MakeConnectionURL( |
const string& sync_server, |
const string& path, |
bool use_ssl) const { |
@@ -120,8 +142,8 @@ string ServerConnectionManager::Post::MakeConnectionURL( |
return connection_url; |
} |
-int ServerConnectionManager::Post::ReadResponse(string* out_buffer, |
- int length) { |
+int ServerConnectionManager::Connection::ReadResponse(string* out_buffer, |
+ int length) { |
int bytes_read = buffer_.length(); |
CHECK(length <= bytes_read); |
out_buffer->assign(buffer_); |
@@ -160,14 +182,39 @@ ServerConnectionManager::ServerConnectionManager( |
get_time_path_(kSyncServerGetTimePath), |
error_count_(0), |
server_status_(HttpResponse::NONE), |
- server_reachable_(false) { |
+ server_reachable_(false), |
+ terminated_(false), |
+ active_connection_(NULL) { |
} |
ServerConnectionManager::~ServerConnectionManager() { |
} |
+ServerConnectionManager::Connection* |
+ServerConnectionManager::MakeActiveConnection() { |
+ base::AutoLock lock(terminate_connection_lock_); |
+ DCHECK(!active_connection_); |
+ if (terminated_) |
+ return NULL; |
+ |
+ active_connection_ = MakeConnection(); |
jar (doing other things)
2011/09/07 06:47:41
It is usually best practice to use locks to only p
tim (not reviewing)
2011/09/07 14:46:56
Thanks for your review Jim. I get the concerns wi
|
+ return active_connection_; |
+} |
+ |
+void ServerConnectionManager::OnConnectionDestroyed(Connection* connection) { |
+ DCHECK(connection); |
+ base::AutoLock lock(terminate_connection_lock_); |
+ // |active_connection_| can be NULL already if it was aborted. Also, |
+ // it can legitimately be a different Connection object if a new Connection |
+ // was created after a previous one was Aborted and destroyed. |
+ if (active_connection_ != connection) |
+ return; |
+ |
+ active_connection_ = NULL; |
+} |
+ |
void ServerConnectionManager::NotifyStatusChanged() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_, |
OnServerConnectionEvent( |
ServerConnectionEvent(server_status_, server_reachable_))); |
@@ -175,7 +222,7 @@ void ServerConnectionManager::NotifyStatusChanged() { |
bool ServerConnectionManager::PostBufferWithCachedAuth( |
PostBufferParams* params, ScopedServerStatusWatcher* watcher) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
string path = |
MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_)); |
return PostBufferToPath(params, path, auth_token(), watcher); |
@@ -184,7 +231,7 @@ bool ServerConnectionManager::PostBufferWithCachedAuth( |
bool ServerConnectionManager::PostBufferToPath(PostBufferParams* params, |
const string& path, const string& auth_token, |
ScopedServerStatusWatcher* watcher) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(watcher != NULL); |
if (auth_token.empty()) { |
@@ -192,9 +239,18 @@ bool ServerConnectionManager::PostBufferToPath(PostBufferParams* params, |
return false; |
} |
- scoped_ptr<Post> post(MakePost()); |
- bool ok = post->Init(path.c_str(), auth_token, params->buffer_in, |
- ¶ms->response); |
+ // When our connection object falls out of scope, it clears itself from |
+ // active_connection_. |
+ ScopedConnectionHelper post(this, MakeActiveConnection()); |
+ if (!post.get()) { |
+ params->response.server_status = HttpResponse::CONNECTION_UNAVAILABLE; |
+ return false; |
+ } |
+ |
+ // Note that |post| may be aborted by now, which will just cause Init to fail |
+ // with CONNECTION_UNAVAILABLE. |
+ bool ok = post.get()->Init( |
+ path.c_str(), auth_token, params->buffer_in, ¶ms->response); |
if (params->response.server_status == HttpResponse::SYNC_AUTH_ERROR) { |
InvalidateAndClearAuthToken(); |
@@ -205,7 +261,8 @@ bool ServerConnectionManager::PostBufferToPath(PostBufferParams* params, |
return false; |
} |
- if (post->ReadBufferResponse(¶ms->buffer_out, ¶ms->response, true)) { |
+ if (post.get()->ReadBufferResponse( |
+ ¶ms->buffer_out, ¶ms->response, true)) { |
params->response.server_status = HttpResponse::SERVER_CONNECTION_OK; |
server_reachable_ = true; |
return true; |
@@ -214,7 +271,8 @@ bool ServerConnectionManager::PostBufferToPath(PostBufferParams* params, |
} |
bool ServerConnectionManager::CheckTime(int32* out_time) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
// Verify that the server really is reachable by checking the time. We need |
// to do this because of wifi interstitials that intercept messages from the |
// client and return HTTP OK instead of a redirect. |
@@ -223,7 +281,9 @@ bool ServerConnectionManager::CheckTime(int32* out_time) { |
string post_body = "command=get_time"; |
for (int i = 0 ; i < 3; i++) { |
- scoped_ptr<Post> post(MakePost()); |
+ ScopedConnectionHelper post(this, MakeActiveConnection()); |
+ if (!post.get()) |
+ break; |
// Note that the server's get_time path doesn't require authentication. |
string get_time_path = |
@@ -231,7 +291,7 @@ bool ServerConnectionManager::CheckTime(int32* out_time) { |
VLOG(1) << "Requesting get_time from:" << get_time_path; |
string blank_post_body; |
- bool ok = post->Init(get_time_path.c_str(), blank_post_body, |
+ bool ok = post.get()->Init(get_time_path.c_str(), blank_post_body, |
blank_post_body, &response); |
if (!ok) { |
VLOG(1) << "Unable to check the time"; |
@@ -240,7 +300,7 @@ bool ServerConnectionManager::CheckTime(int32* out_time) { |
string time_response; |
time_response.resize( |
static_cast<string::size_type>(response.content_length)); |
- ok = post->ReadDownloadResponse(&response, &time_response); |
+ ok = post.get()->ReadDownloadResponse(&response, &time_response); |
if (!ok || string::npos != |
time_response.find_first_not_of("0123456789")) { |
LOG(ERROR) << "unable to read a non-numeric response from get_time:" |
@@ -256,18 +316,18 @@ bool ServerConnectionManager::CheckTime(int32* out_time) { |
} |
bool ServerConnectionManager::IsServerReachable() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
int32 time; |
return CheckTime(&time); |
} |
bool ServerConnectionManager::IsUserAuthenticated() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
return IsGoodReplyFromServer(server_status_); |
} |
bool ServerConnectionManager::CheckServerReachable() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
const bool server_is_reachable = IsServerReachable(); |
if (server_reachable_ != server_is_reachable) { |
server_reachable_ = server_is_reachable; |
@@ -277,7 +337,7 @@ bool ServerConnectionManager::CheckServerReachable() { |
} |
bool ServerConnectionManager::IncrementErrorCount() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
error_count_++; |
if (error_count_ > kMaxConnectionErrorsBeforeReset) { |
@@ -298,7 +358,7 @@ bool ServerConnectionManager::IncrementErrorCount() { |
void ServerConnectionManager::SetServerParameters(const string& server_url, |
int port, |
bool use_ssl) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
sync_server_ = server_url; |
sync_server_port_ = port; |
use_ssl_ = use_ssl; |
@@ -333,20 +393,32 @@ std::string ServerConnectionManager::GetServerHost() const { |
void ServerConnectionManager::AddListener( |
ServerConnectionEventListener* listener) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
listeners_.AddObserver(listener); |
} |
void ServerConnectionManager::RemoveListener( |
ServerConnectionEventListener* listener) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
listeners_.RemoveObserver(listener); |
} |
-ServerConnectionManager::Post* ServerConnectionManager::MakePost() { |
+ServerConnectionManager::Connection* ServerConnectionManager::MakeConnection() |
+{ |
return NULL; // For testing. |
} |
+void ServerConnectionManager::TerminateAllIO() { |
+ base::AutoLock lock(terminate_connection_lock_); |
+ terminated_ = true; |
+ if (active_connection_) |
+ active_connection_->Abort(); |
+ |
+ // Sever our ties to this connection object. Note that it still may exist, |
+ // since we don't own it, but it has been neutered. |
+ active_connection_ = NULL; |
+} |
+ |
bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm, |
syncable::DirectoryManager* manager, |
const std::string& share) { |