• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HttpResponseHttpResponse100   HttpResponse()
101       : response_code(kUnsetResponseCode),
102         content_length(kUnsetContentLength),
103         payload_length(kUnsetPayloadLength),
104         server_status(NONE) {}
105 };
106 
IsGoodReplyFromServer(HttpResponse::ServerConnectionCode code)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 
IsChannelShutdownEventServerConnectionEvent120   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;
ServerConnectionEvent2ServerConnectionEvent2132   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:
~ServerConnectionEventListener()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:
Post(ServerConnectionManager * scm)185     explicit Post(ServerConnectionManager* scm) : scm_(scm), timing_info_(0) {
186     }
~Post()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 
set_timing_info(RequestTimingInfo * timing_info)199     void set_timing_info(RequestTimingInfo* timing_info) {
200       timing_info_ = timing_info;
201     }
timing_info()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 
GetServerParams(std::string * server,int * server_port,bool * use_ssl)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 
channel()258   inline Channel* channel() const { return channel_; }
259 
260   void AddListener(ServerConnectionEventListener* listener);
261   void RemoveListener(ServerConnectionEventListener* listener);
262 
user_agent()263   inline std::string user_agent() const { return user_agent_; }
264 
server_status()265   inline HttpResponse::ServerConnectionCode server_status() const {
266     return server_status_;
267   }
268 
server_reachable()269   inline bool server_reachable() const { return server_reachable_; }
270 
client_id()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 
terminate_all_io()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 
set_client_id(const std::string & client_id)298   void set_client_id(const std::string& client_id) {
299     DCHECK(client_id_.empty());
300     client_id_.assign(client_id);
301   }
302 
set_auth_token(const std::string & auth_token)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 
auth_token()309   const std::string auth_token() const {
310     base::AutoLock lock(auth_token_mutex_);
311     return auth_token_;
312   }
313 
314  protected:
proto_sync_path()315   inline std::string proto_sync_path() const {
316     base::AutoLock lock(path_mutex_);
317     return proto_sync_path_;
318   }
319 
get_time_path()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