Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/engine/net/server_connection_manager.h" | 5 #include "chrome/browser/sync/engine/net/server_connection_manager.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 | 8 |
| 9 #include <ostream> | 9 #include <ostream> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 125 int bytes_read = buffer_.length(); | 125 int bytes_read = buffer_.length(); |
| 126 CHECK(length <= bytes_read); | 126 CHECK(length <= bytes_read); |
| 127 out_buffer->assign(buffer_); | 127 out_buffer->assign(buffer_); |
| 128 return bytes_read; | 128 return bytes_read; |
| 129 } | 129 } |
| 130 | 130 |
| 131 ScopedServerStatusWatcher::ScopedServerStatusWatcher( | 131 ScopedServerStatusWatcher::ScopedServerStatusWatcher( |
| 132 ServerConnectionManager* conn_mgr, HttpResponse* response) | 132 ServerConnectionManager* conn_mgr, HttpResponse* response) |
| 133 : conn_mgr_(conn_mgr), | 133 : conn_mgr_(conn_mgr), |
| 134 response_(response), | 134 response_(response), |
| 135 reset_count_(conn_mgr->reset_count_), | |
| 136 server_reachable_(conn_mgr->server_reachable_) { | 135 server_reachable_(conn_mgr->server_reachable_) { |
| 137 response->server_status = conn_mgr->server_status_; | 136 response->server_status = conn_mgr->server_status_; |
| 138 } | 137 } |
| 139 | 138 |
| 140 ScopedServerStatusWatcher::~ScopedServerStatusWatcher() { | 139 ScopedServerStatusWatcher::~ScopedServerStatusWatcher() { |
| 141 // Don't update the status of the connection if it has been reset. | |
| 142 // TODO(timsteele): Do we need this? Is this used by multiple threads? | |
| 143 if (reset_count_ != conn_mgr_->reset_count_) | |
| 144 return; | |
| 145 if (conn_mgr_->server_status_ != response_->server_status) { | 140 if (conn_mgr_->server_status_ != response_->server_status) { |
|
lipalani1
2011/08/24 20:35:28
It is not a big deal if it is not easy. But we mus
tim (not reviewing)
2011/08/25 16:21:46
Good idea, looking into it.
| |
| 146 conn_mgr_->server_status_ = response_->server_status; | 141 conn_mgr_->server_status_ = response_->server_status; |
| 147 conn_mgr_->NotifyStatusChanged(); | 142 conn_mgr_->NotifyStatusChanged(); |
| 148 return; | 143 return; |
| 149 } | 144 } |
| 150 // Notify if we've gone on or offline. | 145 // Notify if we've gone on or offline. |
| 151 if (server_reachable_ != conn_mgr_->server_reachable_) | 146 if (server_reachable_ != conn_mgr_->server_reachable_) |
| 152 conn_mgr_->NotifyStatusChanged(); | 147 conn_mgr_->NotifyStatusChanged(); |
| 153 } | 148 } |
| 154 | 149 |
| 155 ServerConnectionManager::ServerConnectionManager( | 150 ServerConnectionManager::ServerConnectionManager( |
| 156 const string& server, | 151 const string& server, |
| 157 int port, | 152 int port, |
| 158 bool use_ssl, | 153 bool use_ssl, |
| 159 const string& user_agent) | 154 const string& user_agent) |
| 160 : sync_server_(server), | 155 : sync_server_(server), |
| 161 sync_server_port_(port), | 156 sync_server_port_(port), |
| 162 user_agent_(user_agent), | 157 user_agent_(user_agent), |
| 163 use_ssl_(use_ssl), | 158 use_ssl_(use_ssl), |
| 164 proto_sync_path_(kSyncServerSyncPath), | 159 proto_sync_path_(kSyncServerSyncPath), |
| 165 get_time_path_(kSyncServerGetTimePath), | 160 get_time_path_(kSyncServerGetTimePath), |
| 166 error_count_(0), | 161 error_count_(0), |
| 167 listeners_(new ObserverListThreadSafe<ServerConnectionEventListener>()), | |
| 168 server_status_(HttpResponse::NONE), | 162 server_status_(HttpResponse::NONE), |
| 169 server_reachable_(false), | 163 server_reachable_(false) { |
| 170 reset_count_(0), | |
| 171 terminate_all_io_(false) { | |
| 172 } | 164 } |
| 173 | 165 |
| 174 ServerConnectionManager::~ServerConnectionManager() { | 166 ServerConnectionManager::~ServerConnectionManager() { |
|
lipalani1
2011/08/24 20:35:28
Can you add a CHECK here?(rather than a DCHECK. Is
tim (not reviewing)
2011/08/25 16:21:46
My issue with this is that NonThreadSafe by defaul
| |
| 175 } | 167 } |
| 176 | 168 |
| 177 void ServerConnectionManager::NotifyStatusChanged() { | 169 void ServerConnectionManager::NotifyStatusChanged() { |
| 178 listeners_->Notify(&ServerConnectionEventListener::OnServerConnectionEvent, | 170 DCHECK(CalledOnValidThread()); |
| 179 ServerConnectionEvent(server_status_, server_reachable_)); | 171 FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_, |
| 172 OnServerConnectionEvent( | |
| 173 ServerConnectionEvent(server_status_, server_reachable_))); | |
| 180 } | 174 } |
| 181 | 175 |
| 182 bool ServerConnectionManager::PostBufferWithCachedAuth( | 176 bool ServerConnectionManager::PostBufferWithCachedAuth( |
| 183 const PostBufferParams* params, ScopedServerStatusWatcher* watcher) { | 177 const PostBufferParams* params, ScopedServerStatusWatcher* watcher) { |
| 178 DCHECK(CalledOnValidThread()); | |
| 184 string path = | 179 string path = |
| 185 MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_)); | 180 MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_)); |
| 186 return PostBufferToPath(params, path, auth_token(), watcher); | 181 return PostBufferToPath(params, path, auth_token(), watcher); |
| 187 } | 182 } |
| 188 | 183 |
| 189 bool ServerConnectionManager::PostBufferToPath(const PostBufferParams* params, | 184 bool ServerConnectionManager::PostBufferToPath(const PostBufferParams* params, |
| 190 const string& path, const string& auth_token, | 185 const string& path, const string& auth_token, |
| 191 ScopedServerStatusWatcher* watcher) { | 186 ScopedServerStatusWatcher* watcher) { |
| 187 DCHECK(CalledOnValidThread()); | |
| 192 DCHECK(watcher != NULL); | 188 DCHECK(watcher != NULL); |
| 193 | 189 |
| 194 if (auth_token.empty()) { | 190 if (auth_token.empty()) { |
| 195 params->response->server_status = HttpResponse::SYNC_AUTH_ERROR; | 191 params->response->server_status = HttpResponse::SYNC_AUTH_ERROR; |
| 196 return false; | 192 return false; |
| 197 } | 193 } |
| 198 | 194 |
| 199 scoped_ptr<Post> post(MakePost()); | 195 scoped_ptr<Post> post(MakePost()); |
| 200 post->set_timing_info(params->timing_info); | 196 post->set_timing_info(params->timing_info); |
| 201 bool ok = post->Init(path.c_str(), auth_token, params->buffer_in, | 197 bool ok = post->Init(path.c_str(), auth_token, params->buffer_in, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 212 | 208 |
| 213 if (post->ReadBufferResponse(params->buffer_out, params->response, true)) { | 209 if (post->ReadBufferResponse(params->buffer_out, params->response, true)) { |
| 214 params->response->server_status = HttpResponse::SERVER_CONNECTION_OK; | 210 params->response->server_status = HttpResponse::SERVER_CONNECTION_OK; |
| 215 server_reachable_ = true; | 211 server_reachable_ = true; |
| 216 return true; | 212 return true; |
| 217 } | 213 } |
| 218 return false; | 214 return false; |
| 219 } | 215 } |
| 220 | 216 |
| 221 bool ServerConnectionManager::CheckTime(int32* out_time) { | 217 bool ServerConnectionManager::CheckTime(int32* out_time) { |
| 218 DCHECK(CalledOnValidThread()); | |
| 222 // Verify that the server really is reachable by checking the time. We need | 219 // Verify that the server really is reachable by checking the time. We need |
| 223 // to do this because of wifi interstitials that intercept messages from the | 220 // to do this because of wifi interstitials that intercept messages from the |
| 224 // client and return HTTP OK instead of a redirect. | 221 // client and return HTTP OK instead of a redirect. |
| 225 HttpResponse response; | 222 HttpResponse response; |
| 226 ScopedServerStatusWatcher watcher(this, &response); | 223 ScopedServerStatusWatcher watcher(this, &response); |
| 227 string post_body = "command=get_time"; | 224 string post_body = "command=get_time"; |
| 228 | 225 |
| 229 // We only retry the CheckTime call if we were reset during the CheckTime | 226 for (int i = 0 ; i < 3; i++) { |
| 230 // attempt. We only try 3 times in case we're in a reset loop elsewhere. | |
| 231 base::subtle::AtomicWord start_reset_count = reset_count_ - 1; | |
| 232 for (int i = 0 ; i < 3 && start_reset_count != reset_count_ ; i++) { | |
| 233 start_reset_count = reset_count_; | |
| 234 scoped_ptr<Post> post(MakePost()); | 227 scoped_ptr<Post> post(MakePost()); |
| 235 | 228 |
| 236 // Note that the server's get_time path doesn't require authentication. | 229 // Note that the server's get_time path doesn't require authentication. |
| 237 string get_time_path = | 230 string get_time_path = |
| 238 MakeSyncServerPath(kSyncServerGetTimePath, post_body); | 231 MakeSyncServerPath(kSyncServerGetTimePath, post_body); |
| 239 VLOG(1) << "Requesting get_time from:" << get_time_path; | 232 VLOG(1) << "Requesting get_time from:" << get_time_path; |
| 240 | 233 |
| 241 string blank_post_body; | 234 string blank_post_body; |
| 242 bool ok = post->Init(get_time_path.c_str(), blank_post_body, | 235 bool ok = post->Init(get_time_path.c_str(), blank_post_body, |
| 243 blank_post_body, &response); | 236 blank_post_body, &response); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 257 } | 250 } |
| 258 *out_time = atoi(time_response.c_str()); | 251 *out_time = atoi(time_response.c_str()); |
| 259 VLOG(1) << "Server was reachable."; | 252 VLOG(1) << "Server was reachable."; |
| 260 return true; | 253 return true; |
| 261 } | 254 } |
| 262 IncrementErrorCount(); | 255 IncrementErrorCount(); |
| 263 return false; | 256 return false; |
| 264 } | 257 } |
| 265 | 258 |
| 266 bool ServerConnectionManager::IsServerReachable() { | 259 bool ServerConnectionManager::IsServerReachable() { |
| 260 DCHECK(CalledOnValidThread()); | |
| 267 int32 time; | 261 int32 time; |
| 268 return CheckTime(&time); | 262 return CheckTime(&time); |
| 269 } | 263 } |
| 270 | 264 |
| 271 bool ServerConnectionManager::IsUserAuthenticated() { | 265 bool ServerConnectionManager::IsUserAuthenticated() { |
| 266 DCHECK(CalledOnValidThread()); | |
| 272 return IsGoodReplyFromServer(server_status_); | 267 return IsGoodReplyFromServer(server_status_); |
| 273 } | 268 } |
| 274 | 269 |
| 275 bool ServerConnectionManager::CheckServerReachable() { | 270 bool ServerConnectionManager::CheckServerReachable() { |
| 271 DCHECK(CalledOnValidThread()); | |
| 276 const bool server_is_reachable = IsServerReachable(); | 272 const bool server_is_reachable = IsServerReachable(); |
| 277 if (server_reachable_ != server_is_reachable) { | 273 if (server_reachable_ != server_is_reachable) { |
| 278 server_reachable_ = server_is_reachable; | 274 server_reachable_ = server_is_reachable; |
| 279 NotifyStatusChanged(); | 275 NotifyStatusChanged(); |
| 280 } | 276 } |
| 281 return server_is_reachable; | 277 return server_is_reachable; |
| 282 } | 278 } |
| 283 | 279 |
| 284 void ServerConnectionManager::kill() { | |
| 285 { | |
| 286 base::AutoLock lock(terminate_all_io_mutex_); | |
| 287 terminate_all_io_ = true; | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 void ServerConnectionManager::ResetConnection() { | |
| 292 base::subtle::NoBarrier_AtomicIncrement(&reset_count_, 1); | |
| 293 } | |
| 294 | |
| 295 bool ServerConnectionManager::IncrementErrorCount() { | 280 bool ServerConnectionManager::IncrementErrorCount() { |
| 296 error_count_mutex_.Acquire(); | 281 DCHECK(CalledOnValidThread()); |
| 297 error_count_++; | 282 error_count_++; |
| 298 | 283 |
| 299 if (error_count_ > kMaxConnectionErrorsBeforeReset) { | 284 if (error_count_ > kMaxConnectionErrorsBeforeReset) { |
| 300 error_count_ = 0; | 285 error_count_ = 0; |
| 301 | 286 |
| 302 // Be careful with this mutex because calling out to other methods can | |
| 303 // result in being called back. Unlock it here to prevent any potential | |
| 304 // double-acquisitions. | |
| 305 error_count_mutex_.Release(); | |
| 306 | |
| 307 if (!IsServerReachable()) { | 287 if (!IsServerReachable()) { |
| 308 LOG(WARNING) << "Too many connection failures, server is not reachable. " | 288 LOG(WARNING) << "Too many connection failures, server is not reachable. " |
| 309 << "Resetting connections."; | 289 << "Resetting connections."; |
| 310 ResetConnection(); | |
| 311 } else { | 290 } else { |
| 312 LOG(WARNING) << "Multiple connection failures while server is reachable."; | 291 LOG(WARNING) << "Multiple connection failures while server is reachable."; |
| 313 } | 292 } |
| 314 return false; | 293 return false; |
| 315 } | 294 } |
| 316 | 295 |
| 317 error_count_mutex_.Release(); | |
| 318 return true; | 296 return true; |
| 319 } | 297 } |
| 320 | 298 |
| 321 void ServerConnectionManager::SetServerParameters(const string& server_url, | 299 void ServerConnectionManager::SetServerParameters(const string& server_url, |
| 322 int port, | 300 int port, |
| 323 bool use_ssl) { | 301 bool use_ssl) { |
|
lipalani1
2011/08/24 20:35:28
Add dcheck here too.
tim (not reviewing)
2011/08/25 16:21:46
Done.
| |
| 324 { | 302 sync_server_ = server_url; |
| 325 base::AutoLock lock(server_parameters_mutex_); | 303 sync_server_port_ = port; |
| 326 sync_server_ = server_url; | 304 use_ssl_ = use_ssl; |
| 327 sync_server_port_ = port; | |
| 328 use_ssl_ = use_ssl; | |
| 329 } | |
| 330 } | 305 } |
| 331 | 306 |
| 332 // Returns the current server parameters in server_url and port. | 307 // Returns the current server parameters in server_url and port. |
| 333 void ServerConnectionManager::GetServerParameters(string* server_url, | 308 void ServerConnectionManager::GetServerParameters(string* server_url, |
| 334 int* port, | 309 int* port, |
| 335 bool* use_ssl) const { | 310 bool* use_ssl) const { |
| 336 base::AutoLock lock(server_parameters_mutex_); | |
| 337 if (server_url != NULL) | 311 if (server_url != NULL) |
| 338 *server_url = sync_server_; | 312 *server_url = sync_server_; |
| 339 if (port != NULL) | 313 if (port != NULL) |
| 340 *port = sync_server_port_; | 314 *port = sync_server_port_; |
| 341 if (use_ssl != NULL) | 315 if (use_ssl != NULL) |
| 342 *use_ssl = use_ssl_; | 316 *use_ssl = use_ssl_; |
| 343 } | 317 } |
| 344 | 318 |
| 345 std::string ServerConnectionManager::GetServerHost() const { | 319 std::string ServerConnectionManager::GetServerHost() const { |
| 346 string server_url; | 320 string server_url; |
| 347 int port; | 321 int port; |
| 348 bool use_ssl; | 322 bool use_ssl; |
| 349 GetServerParameters(&server_url, &port, &use_ssl); | 323 GetServerParameters(&server_url, &port, &use_ssl); |
| 350 // For unit tests. | 324 // For unit tests. |
| 351 if (server_url.empty()) | 325 if (server_url.empty()) |
| 352 return std::string(); | 326 return std::string(); |
| 353 // We just want the hostname, so we don't need to switch on use_ssl. | 327 // We just want the hostname, so we don't need to switch on use_ssl. |
| 354 server_url = "http://" + server_url; | 328 server_url = "http://" + server_url; |
| 355 GURL gurl(server_url); | 329 GURL gurl(server_url); |
| 356 DCHECK(gurl.is_valid()) << gurl; | 330 DCHECK(gurl.is_valid()) << gurl; |
| 357 return gurl.host(); | 331 return gurl.host(); |
| 358 } | 332 } |
| 359 | 333 |
| 360 void ServerConnectionManager::AddListener( | 334 void ServerConnectionManager::AddListener( |
| 361 ServerConnectionEventListener* listener) { | 335 ServerConnectionEventListener* listener) { |
|
lipalani1
2011/08/24 20:35:28
here too.
tim (not reviewing)
2011/08/25 16:21:46
Done.
| |
| 362 listeners_->AddObserver(listener); | 336 listeners_.AddObserver(listener); |
| 363 } | 337 } |
| 364 | 338 |
| 365 void ServerConnectionManager::RemoveListener( | 339 void ServerConnectionManager::RemoveListener( |
| 366 ServerConnectionEventListener* listener) { | 340 ServerConnectionEventListener* listener) { |
|
lipalani1
2011/08/24 20:35:28
Here too.
tim (not reviewing)
2011/08/25 16:21:46
Done.
| |
| 367 listeners_->RemoveObserver(listener); | 341 listeners_.RemoveObserver(listener); |
| 368 } | 342 } |
| 369 | 343 |
| 370 ServerConnectionManager::Post* ServerConnectionManager::MakePost() { | 344 ServerConnectionManager::Post* ServerConnectionManager::MakePost() { |
| 371 return NULL; // For testing. | 345 return NULL; // For testing. |
| 372 } | 346 } |
| 373 | 347 |
| 374 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm, | 348 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm, |
| 375 syncable::DirectoryManager* manager, | 349 syncable::DirectoryManager* manager, |
| 376 const std::string& share) { | 350 const std::string& share) { |
| 377 syncable::ScopedDirLookup dir(manager, share); | 351 syncable::ScopedDirLookup dir(manager, share); |
| 378 if (!dir.good()) { | 352 if (!dir.good()) { |
| 379 VLOG(1) << "Dir lookup failed"; | 353 VLOG(1) << "Dir lookup failed"; |
| 380 return false; | 354 return false; |
| 381 } | 355 } |
| 382 string birthday = dir->store_birthday(); | 356 string birthday = dir->store_birthday(); |
| 383 if (!birthday.empty()) | 357 if (!birthday.empty()) |
| 384 csm->set_store_birthday(birthday); | 358 csm->set_store_birthday(birthday); |
| 385 csm->set_share(share); | 359 csm->set_share(share); |
| 386 return true; | 360 return true; |
| 387 } | 361 } |
| 388 | 362 |
| 389 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) { | 363 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) { |
| 390 s << " Response Code (bogus on error): " << hr.response_code; | 364 s << " Response Code (bogus on error): " << hr.response_code; |
| 391 s << " Content-Length (bogus on error): " << hr.content_length; | 365 s << " Content-Length (bogus on error): " << hr.content_length; |
| 392 s << " Server Status: " << hr.server_status; | 366 s << " Server Status: " << hr.server_status; |
| 393 return s; | 367 return s; |
| 394 } | 368 } |
| 395 | 369 |
| 396 } // namespace browser_sync | 370 } // namespace browser_sync |
| OLD | NEW |