Chromium Code Reviews| 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) { |