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) { |
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() { |
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) { |
324 { | 302 DCHECK(CalledOnValidThread()); |
325 base::AutoLock lock(server_parameters_mutex_); | 303 sync_server_ = server_url; |
326 sync_server_ = server_url; | 304 sync_server_port_ = port; |
327 sync_server_port_ = port; | 305 use_ssl_ = use_ssl; |
328 use_ssl_ = use_ssl; | |
329 } | |
330 } | 306 } |
331 | 307 |
332 // Returns the current server parameters in server_url and port. | 308 // Returns the current server parameters in server_url and port. |
333 void ServerConnectionManager::GetServerParameters(string* server_url, | 309 void ServerConnectionManager::GetServerParameters(string* server_url, |
334 int* port, | 310 int* port, |
335 bool* use_ssl) const { | 311 bool* use_ssl) const { |
336 base::AutoLock lock(server_parameters_mutex_); | |
337 if (server_url != NULL) | 312 if (server_url != NULL) |
338 *server_url = sync_server_; | 313 *server_url = sync_server_; |
339 if (port != NULL) | 314 if (port != NULL) |
340 *port = sync_server_port_; | 315 *port = sync_server_port_; |
341 if (use_ssl != NULL) | 316 if (use_ssl != NULL) |
342 *use_ssl = use_ssl_; | 317 *use_ssl = use_ssl_; |
343 } | 318 } |
344 | 319 |
345 std::string ServerConnectionManager::GetServerHost() const { | 320 std::string ServerConnectionManager::GetServerHost() const { |
346 string server_url; | 321 string server_url; |
347 int port; | 322 int port; |
348 bool use_ssl; | 323 bool use_ssl; |
349 GetServerParameters(&server_url, &port, &use_ssl); | 324 GetServerParameters(&server_url, &port, &use_ssl); |
350 // For unit tests. | 325 // For unit tests. |
351 if (server_url.empty()) | 326 if (server_url.empty()) |
352 return std::string(); | 327 return std::string(); |
353 // We just want the hostname, so we don't need to switch on use_ssl. | 328 // We just want the hostname, so we don't need to switch on use_ssl. |
354 server_url = "http://" + server_url; | 329 server_url = "http://" + server_url; |
355 GURL gurl(server_url); | 330 GURL gurl(server_url); |
356 DCHECK(gurl.is_valid()) << gurl; | 331 DCHECK(gurl.is_valid()) << gurl; |
357 return gurl.host(); | 332 return gurl.host(); |
358 } | 333 } |
359 | 334 |
360 void ServerConnectionManager::AddListener( | 335 void ServerConnectionManager::AddListener( |
361 ServerConnectionEventListener* listener) { | 336 ServerConnectionEventListener* listener) { |
362 listeners_->AddObserver(listener); | 337 DCHECK(CalledOnValidThread()); |
| 338 listeners_.AddObserver(listener); |
363 } | 339 } |
364 | 340 |
365 void ServerConnectionManager::RemoveListener( | 341 void ServerConnectionManager::RemoveListener( |
366 ServerConnectionEventListener* listener) { | 342 ServerConnectionEventListener* listener) { |
367 listeners_->RemoveObserver(listener); | 343 DCHECK(CalledOnValidThread()); |
| 344 listeners_.RemoveObserver(listener); |
368 } | 345 } |
369 | 346 |
370 ServerConnectionManager::Post* ServerConnectionManager::MakePost() { | 347 ServerConnectionManager::Post* ServerConnectionManager::MakePost() { |
371 return NULL; // For testing. | 348 return NULL; // For testing. |
372 } | 349 } |
373 | 350 |
374 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm, | 351 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm, |
375 syncable::DirectoryManager* manager, | 352 syncable::DirectoryManager* manager, |
376 const std::string& share) { | 353 const std::string& share) { |
377 syncable::ScopedDirLookup dir(manager, share); | 354 syncable::ScopedDirLookup dir(manager, share); |
378 if (!dir.good()) { | 355 if (!dir.good()) { |
379 VLOG(1) << "Dir lookup failed"; | 356 VLOG(1) << "Dir lookup failed"; |
380 return false; | 357 return false; |
381 } | 358 } |
382 string birthday = dir->store_birthday(); | 359 string birthday = dir->store_birthday(); |
383 if (!birthday.empty()) | 360 if (!birthday.empty()) |
384 csm->set_store_birthday(birthday); | 361 csm->set_store_birthday(birthday); |
385 csm->set_share(share); | 362 csm->set_share(share); |
386 return true; | 363 return true; |
387 } | 364 } |
388 | 365 |
389 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) { | 366 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) { |
390 s << " Response Code (bogus on error): " << hr.response_code; | 367 s << " Response Code (bogus on error): " << hr.response_code; |
391 s << " Content-Length (bogus on error): " << hr.content_length; | 368 s << " Content-Length (bogus on error): " << hr.content_length; |
392 s << " Server Status: " << hr.server_status; | 369 s << " Server Status: " << hr.server_status; |
393 return s; | 370 return s; |
394 } | 371 } |
395 | 372 |
396 } // namespace browser_sync | 373 } // namespace browser_sync |
OLD | NEW |