1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ 6 #define CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ 7 #pragma once 8 9 #include <iosfwd> 10 #include <string> 11 12 #include "base/atomicops.h" 13 #include "base/observer_list_threadsafe.h" 14 #include "base/string_util.h" 15 #include "base/synchronization/lock.h" 16 #include "chrome/browser/sync/syncable/syncable_id.h" 17 #include "chrome/common/deprecated/event_sys.h" 18 #include "chrome/common/deprecated/event_sys-inl.h" 19 #include "chrome/common/net/http_return.h" 20 21 namespace syncable { 22 class WriteTransaction; 23 class DirectoryManager; 24 } 25 26 namespace sync_pb { 27 class ClientToServerMessage; 28 } 29 30 struct RequestTimingInfo; 31 32 namespace browser_sync { 33 34 class ClientToServerMessage; 35 36 // How many connection errors are accepted before network handles are closed 37 // and reopened. 38 static const int32 kMaxConnectionErrorsBeforeReset = 10; 39 40 static const int32 kUnsetResponseCode = -1; 41 static const int32 kUnsetContentLength = -1; 42 static const int32 kUnsetPayloadLength = -1; 43 44 // HttpResponse gathers the relevant output properties of an HTTP request. 45 // Depending on the value of the server_status code, response_code, and 46 // content_length may not be valid. 47 struct HttpResponse { 48 enum ServerConnectionCode { 49 // For uninitialized state. 50 NONE, 51 52 // CONNECTION_UNAVAILABLE is returned when InternetConnect() fails. 53 CONNECTION_UNAVAILABLE, 54 55 // IO_ERROR is returned when reading/writing to a buffer has failed. 56 IO_ERROR, 57 58 // SYNC_SERVER_ERROR is returned when the HTTP status code indicates that 59 // a non-auth error has occured. 60 SYNC_SERVER_ERROR, 61 62 // SYNC_AUTH_ERROR is returned when the HTTP status code indicates that an 63 // auth error has occured (i.e. a 401 or sync-specific AUTH_INVALID 64 // response) 65 // TODO(tim): Caring about AUTH_INVALID is a layering violation. But 66 // this app-specific logic is being added as a stable branch hotfix so 67 // minimal changes prevail for the moment. Fix this! Bug 35060. 68 SYNC_AUTH_ERROR, 69 70 // All the following connection codes are valid responses from the server. 71 // Means the server is up. If you update this list, be sure to also update 72 // IsGoodReplyFromServer(). 73 74 // SERVER_CONNECTION_OK is returned when request was handled correctly. 75 SERVER_CONNECTION_OK, 76 77 // RETRY is returned when a Commit request fails with a RETRY response from 78 // the server. 79 // 80 // TODO(idana): the server no longer returns RETRY so we should remove this 81 // value. 82 RETRY, 83 }; 84 85 // The HTTP Status code. 86 int64 response_code; 87 88 // The value of the Content-length header. 89 int64 content_length; 90 91 // The size of a download request's payload. 92 int64 payload_length; 93 94 // Value of the Update-Client-Auth header. 95 std::string update_client_auth_header; 96 97 // Identifies the type of failure, if any. 98 ServerConnectionCode server_status; 99 100 HttpResponse() 101 : response_code(kUnsetResponseCode), 102 content_length(kUnsetContentLength), 103 payload_length(kUnsetPayloadLength), 104 server_status(NONE) {} 105 }; 106 107 inline bool IsGoodReplyFromServer(HttpResponse::ServerConnectionCode code) { 108 return code >= HttpResponse::SERVER_CONNECTION_OK; 109 } 110 111 // TODO(tim): Deprecated. 112 struct ServerConnectionEvent { 113 // Traits. 114 typedef ServerConnectionEvent EventType; 115 enum WhatHappened { 116 SHUTDOWN, 117 STATUS_CHANGED 118 }; 119 120 static inline bool IsChannelShutdownEvent(const EventType& event) { 121 return SHUTDOWN == event.what_happened; 122 } 123 124 WhatHappened what_happened; 125 HttpResponse::ServerConnectionCode connection_code; 126 bool server_reachable; 127 }; 128 129 struct ServerConnectionEvent2 { 130 HttpResponse::ServerConnectionCode connection_code; 131 bool server_reachable; 132 ServerConnectionEvent2(HttpResponse::ServerConnectionCode code, 133 bool server_reachable) : 134 connection_code(code), server_reachable(server_reachable) {} 135 }; 136 137 class ServerConnectionEventListener { 138 public: 139 virtual void OnServerConnectionEvent(const ServerConnectionEvent2& event) = 0; 140 protected: 141 virtual ~ServerConnectionEventListener() {} 142 }; 143 144 class ServerConnectionManager; 145 // A helper class that automatically notifies when the status changes. 146 // TODO(tim): This class shouldn't be exposed outside of the implementation, 147 // bug 35060. 148 class ScopedServerStatusWatcher { 149 public: 150 ScopedServerStatusWatcher(ServerConnectionManager* conn_mgr, 151 HttpResponse* response); 152 ~ScopedServerStatusWatcher(); 153 private: 154 ServerConnectionManager* const conn_mgr_; 155 HttpResponse* const response_; 156 // TODO(tim): Should this be Barrier:AtomicIncrement? 157 base::subtle::AtomicWord reset_count_; 158 bool server_reachable_; 159 DISALLOW_COPY_AND_ASSIGN(ScopedServerStatusWatcher); 160 }; 161 162 // Use this class to interact with the sync server. 163 // The ServerConnectionManager currently supports POSTing protocol buffers. 164 // 165 // *** This class is thread safe. In fact, you should consider creating only 166 // one instance for every server that you need to talk to. 167 class ServerConnectionManager { 168 public: 169 typedef EventChannel<ServerConnectionEvent, base::Lock> Channel; 170 171 // buffer_in - will be POSTed 172 // buffer_out - string will be overwritten with response 173 struct PostBufferParams { 174 const std::string& buffer_in; 175 std::string* buffer_out; 176 HttpResponse* response; 177 RequestTimingInfo* timing_info; 178 }; 179 180 // Abstract class providing network-layer functionality to the 181 // ServerConnectionManager. Subclasses implement this using an HTTP stack of 182 // their choice. 183 class Post { 184 public: 185 explicit Post(ServerConnectionManager* scm) : scm_(scm), timing_info_(0) { 186 } 187 virtual ~Post() { } 188 189 // Called to initialize and perform an HTTP POST. 190 virtual bool Init(const char* path, 191 const std::string& auth_token, 192 const std::string& payload, 193 HttpResponse* response) = 0; 194 195 bool ReadBufferResponse(std::string* buffer_out, HttpResponse* response, 196 bool require_response); 197 bool ReadDownloadResponse(HttpResponse* response, std::string* buffer_out); 198 199 void set_timing_info(RequestTimingInfo* timing_info) { 200 timing_info_ = timing_info; 201 } 202 RequestTimingInfo* timing_info() { return timing_info_; } 203 204 protected: 205 std::string MakeConnectionURL(const std::string& sync_server, 206 const std::string& path, 207 bool use_ssl) const; 208 209 void GetServerParams(std::string* server, 210 int* server_port, 211 bool* use_ssl) const { 212 base::AutoLock lock(scm_->server_parameters_mutex_); 213 server->assign(scm_->sync_server_); 214 *server_port = scm_->sync_server_port_; 215 *use_ssl = scm_->use_ssl_; 216 } 217 218 std::string buffer_; 219 ServerConnectionManager* scm_; 220 221 private: 222 int ReadResponse(void* buffer, int length); 223 int ReadResponse(std::string* buffer, int length); 224 RequestTimingInfo* timing_info_; 225 }; 226 227 ServerConnectionManager(const std::string& server, 228 int port, 229 bool use_ssl, 230 const std::string& user_agent); 231 232 virtual ~ServerConnectionManager(); 233 234 // POSTS buffer_in and reads a response into buffer_out. Uses our currently 235 // set auth token in our headers. 236 // 237 // Returns true if executed successfully. 238 virtual bool PostBufferWithCachedAuth(const PostBufferParams* params, 239 ScopedServerStatusWatcher* watcher); 240 241 // Checks the time on the server. Returns false if the request failed. |time| 242 // is an out parameter that stores the value returned from the server. 243 virtual bool CheckTime(int32* out_time); 244 245 // Returns true if sync_server_ is reachable. This method verifies that the 246 // server is pingable and that traffic can be sent to and from it. 247 virtual bool IsServerReachable(); 248 249 // Returns true if user has been successfully authenticated. 250 virtual bool IsUserAuthenticated(); 251 252 // Updates status and broadcasts events on change. 253 bool CheckServerReachable(); 254 255 // Signal the shutdown event to notify listeners. 256 virtual void kill(); 257 258 inline Channel* channel() const { return channel_; } 259 260 void AddListener(ServerConnectionEventListener* listener); 261 void RemoveListener(ServerConnectionEventListener* listener); 262 263 inline std::string user_agent() const { return user_agent_; } 264 265 inline HttpResponse::ServerConnectionCode server_status() const { 266 return server_status_; 267 } 268 269 inline bool server_reachable() const { return server_reachable_; } 270 271 const std::string client_id() const { return client_id_; } 272 273 // This changes the server info used by the connection manager. This allows 274 // a single client instance to talk to different backing servers. This is 275 // typically called during / after authentication so that the server url 276 // can be a function of the user's login id. A side effect of this call is 277 // that ResetConnection is called. 278 void SetServerParameters(const std::string& server_url, 279 int port, 280 bool use_ssl); 281 282 // Returns the current server parameters in server_url, port and use_ssl. 283 void GetServerParameters(std::string* server_url, 284 int* port, 285 bool* use_ssl) const; 286 287 std::string GetServerHost() const; 288 289 bool terminate_all_io() const { 290 base::AutoLock lock(terminate_all_io_mutex_); 291 return terminate_all_io_; 292 } 293 294 // Factory method to create a Post object we can use for communication with 295 // the server. 296 virtual Post* MakePost(); 297 298 void set_client_id(const std::string& client_id) { 299 DCHECK(client_id_.empty()); 300 client_id_.assign(client_id); 301 } 302 303 void set_auth_token(const std::string& auth_token) { 304 // TODO(chron): Consider adding a message loop check here. 305 base::AutoLock lock(auth_token_mutex_); 306 auth_token_.assign(auth_token); 307 } 308 309 const std::string auth_token() const { 310 base::AutoLock lock(auth_token_mutex_); 311 return auth_token_; 312 } 313 314 protected: 315 inline std::string proto_sync_path() const { 316 base::AutoLock lock(path_mutex_); 317 return proto_sync_path_; 318 } 319 320 std::string get_time_path() const { 321 base::AutoLock lock(path_mutex_); 322 return get_time_path_; 323 } 324 325 // Called wherever a failure should be taken as an indication that we may 326 // be experiencing connection difficulties. 327 virtual bool IncrementErrorCount(); 328 329 // NOTE: Tests rely on this protected function being virtual. 330 // 331 // Internal PostBuffer base function. 332 virtual bool PostBufferToPath(const PostBufferParams*, 333 const std::string& path, 334 const std::string& auth_token, 335 ScopedServerStatusWatcher* watcher); 336 337 // Protects access to sync_server_, sync_server_port_ and use_ssl_: 338 mutable base::Lock server_parameters_mutex_; 339 340 // The sync_server_ is the server that requests will be made to. 341 std::string sync_server_; 342 343 // The sync_server_port_ is the port that HTTP requests will be made on. 344 int sync_server_port_; 345 346 // The unique id of the user's client. 347 std::string client_id_; 348 349 // The user-agent string for HTTP. 350 std::string user_agent_; 351 352 // Indicates whether or not requests should be made using HTTPS. 353 bool use_ssl_; 354 355 // The paths we post to. 356 mutable base::Lock path_mutex_; 357 std::string proto_sync_path_; 358 std::string get_time_path_; 359 360 mutable base::Lock auth_token_mutex_; 361 // The auth token to use in authenticated requests. Set by the AuthWatcher. 362 std::string auth_token_; 363 364 base::Lock error_count_mutex_; // Protects error_count_ 365 int error_count_; // Tracks the number of connection errors. 366 367 // TODO(tim): Deprecated. 368 Channel* const channel_; 369 370 scoped_refptr<ObserverListThreadSafe<ServerConnectionEventListener> > 371 listeners_; 372 373 // Volatile so various threads can call server_status() without 374 // synchronization. 375 volatile HttpResponse::ServerConnectionCode server_status_; 376 bool server_reachable_; 377 378 // A counter that is incremented everytime ResetAuthStatus() is called. 379 volatile base::subtle::AtomicWord reset_count_; 380 381 private: 382 friend class Post; 383 friend class ScopedServerStatusWatcher; 384 385 void NotifyStatusChanged(); 386 void ResetConnection(); 387 388 mutable base::Lock terminate_all_io_mutex_; 389 bool terminate_all_io_; // When set to true, terminate all connections asap. 390 DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager); 391 }; 392 393 // Fills a ClientToServerMessage with the appropriate share and birthday 394 // settings. 395 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm, 396 syncable::DirectoryManager* manager, 397 const std::string& share); 398 399 std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr); 400 401 } // namespace browser_sync 402 403 #endif // CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ 404