1 // Copyright 2013 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 GOOGLE_APIS_GCM_ENGINE_MCS_CLIENT_H_ 6 #define GOOGLE_APIS_GCM_ENGINE_MCS_CLIENT_H_ 7 8 #include <deque> 9 #include <map> 10 #include <string> 11 #include <vector> 12 13 #include "base/files/file_path.h" 14 #include "base/memory/linked_ptr.h" 15 #include "base/memory/weak_ptr.h" 16 #include "google_apis/gcm/base/gcm_export.h" 17 #include "google_apis/gcm/base/mcs_message.h" 18 #include "google_apis/gcm/engine/connection_handler.h" 19 #include "google_apis/gcm/engine/gcm_store.h" 20 #include "google_apis/gcm/engine/heartbeat_manager.h" 21 22 namespace base { 23 class Clock; 24 } // namespace base 25 26 namespace google { 27 namespace protobuf { 28 class MessageLite; 29 } // namespace protobuf 30 } // namespace google 31 32 namespace mcs_proto { 33 class LoginRequest; 34 } 35 36 namespace gcm { 37 38 class CollapseKey; 39 class ConnectionFactory; 40 class GCMStatsRecorder; 41 struct ReliablePacketInfo; 42 43 // An MCS client. This client is in charge of all communications with an 44 // MCS endpoint, and is capable of reliably sending/receiving GCM messages. 45 // NOTE: Not thread safe. This class should live on the same thread as that 46 // network requests are performed on. 47 class GCM_EXPORT MCSClient { 48 public: 49 // Any change made to this enum should have corresponding change in the 50 // GetStateString(...) function. 51 enum State { 52 UNINITIALIZED, // Uninitialized. 53 LOADED, // GCM Load finished, waiting to connect. 54 CONNECTING, // Connection in progress. 55 CONNECTED, // Connected and running. 56 }; 57 58 // Any change made to this enum should have corresponding change in the 59 // GetMessageSendStatusString(...) function in mcs_client.cc. 60 enum MessageSendStatus { 61 // Message was queued succcessfully. 62 QUEUED, 63 // Message was sent to the server and the ACK was received. 64 SENT, 65 // Message not saved, because total queue size limit reached. 66 QUEUE_SIZE_LIMIT_REACHED, 67 // Message not saved, because app queue size limit reached. 68 APP_QUEUE_SIZE_LIMIT_REACHED, 69 // Message too large to send. 70 MESSAGE_TOO_LARGE, 71 // Message not send becuase of TTL = 0 and no working connection. 72 NO_CONNECTION_ON_ZERO_TTL, 73 // Message exceeded TTL. 74 TTL_EXCEEDED, 75 76 // NOTE: always keep this entry at the end. Add new status types only 77 // immediately above this line. Make sure to update the corresponding 78 // histogram enum accordingly. 79 SEND_STATUS_COUNT 80 }; 81 82 // Callback for MCSClient's error conditions. 83 // TODO(fgorski): Keeping it as a callback with intention to add meaningful 84 // error information. 85 typedef base::Callback<void()> ErrorCallback; 86 // Callback when a message is received. 87 typedef base::Callback<void(const MCSMessage& message)> 88 OnMessageReceivedCallback; 89 // Callback when a message is sent (and receipt has been acknowledged by 90 // the MCS endpoint). 91 typedef base::Callback< 92 void(int64 user_serial_number, 93 const std::string& app_id, 94 const std::string& message_id, 95 MessageSendStatus status)> OnMessageSentCallback; 96 97 MCSClient(const std::string& version_string, 98 base::Clock* clock, 99 ConnectionFactory* connection_factory, 100 GCMStore* gcm_store, 101 GCMStatsRecorder* recorder); 102 virtual ~MCSClient(); 103 104 // Initialize the client. Will load any previous id/token information as well 105 // as unacknowledged message information from the GCM storage, if it exists, 106 // passing the id/token information back via |initialization_callback| along 107 // with a |success == true| result. If no GCM information is present (and 108 // this is therefore a fresh client), a clean GCM store will be created and 109 // values of 0 will be returned via |initialization_callback| with 110 // |success == true|. 111 /// If an error loading the GCM store is encountered, 112 // |initialization_callback| will be invoked with |success == false|. 113 void Initialize(const ErrorCallback& initialization_callback, 114 const OnMessageReceivedCallback& message_received_callback, 115 const OnMessageSentCallback& message_sent_callback, 116 scoped_ptr<GCMStore::LoadResult> load_result); 117 118 // Logs the client into the server. Client must be initialized. 119 // |android_id| and |security_token| are optional if this is not a new 120 // client, else they must be non-zero. 121 // Successful login will result in |message_received_callback| being invoked 122 // with a valid LoginResponse. 123 // Login failure (typically invalid id/token) will shut down the client, and 124 // |initialization_callback| to be invoked with |success = false|. 125 virtual void Login(uint64 android_id, uint64 security_token); 126 127 // Sends a message, with or without reliable message queueing (RMQ) support. 128 // Will asynchronously invoke the OnMessageSent callback regardless. 129 // Whether to use RMQ depends on whether the protobuf has |ttl| set or not. 130 // |ttl == 0| denotes the message should only be sent if the connection is 131 // open. |ttl > 0| will keep the message saved for |ttl| seconds, after which 132 // it will be dropped if it was unable to be sent. When a message is dropped, 133 // |message_sent_callback_| is invoked with a TTL expiration error. 134 virtual void SendMessage(const MCSMessage& message); 135 136 // Returns the current state of the client. state()137 State state() const { return state_; } 138 139 // Returns the size of the send message queue. 140 int GetSendQueueSize() const; 141 142 // Returns the size of the resend messaage queue. 143 int GetResendQueueSize() const; 144 145 // Returns text representation of the state enum. 146 std::string GetStateString() const; 147 148 private: 149 typedef uint32 StreamId; 150 typedef std::string PersistentId; 151 typedef std::vector<StreamId> StreamIdList; 152 typedef std::vector<PersistentId> PersistentIdList; 153 typedef std::map<StreamId, PersistentId> StreamIdToPersistentIdMap; 154 typedef linked_ptr<ReliablePacketInfo> MCSPacketInternal; 155 156 // Resets the internal state and builds a new login request, acknowledging 157 // any pending server-to-device messages and rebuilding the send queue 158 // from all unacknowledged device-to-server messages. 159 // Should only be called when the connection has been reset. 160 void ResetStateAndBuildLoginRequest(mcs_proto::LoginRequest* request); 161 162 // Send a heartbeat to the MCS server. 163 void SendHeartbeat(); 164 165 // GCM Store callback. 166 void OnGCMUpdateFinished(bool success); 167 168 // Attempt to send a message. 169 void MaybeSendMessage(); 170 171 // Helper for sending a protobuf along with any unacknowledged ids to the 172 // wire. 173 void SendPacketToWire(ReliablePacketInfo* packet_info); 174 175 // Handle a data message sent to the MCS client system from the MCS server. 176 void HandleMCSDataMesssage( 177 scoped_ptr<google::protobuf::MessageLite> protobuf); 178 179 // Handle a packet received over the wire. 180 void HandlePacketFromWire(scoped_ptr<google::protobuf::MessageLite> protobuf); 181 182 // ReliableMessageQueue acknowledgment helpers. 183 // Handle a StreamAck sent by the server confirming receipt of all 184 // messages up to the message with stream id |last_stream_id_received|. 185 void HandleStreamAck(StreamId last_stream_id_received_); 186 // Handle a SelectiveAck sent by the server confirming all messages 187 // in |id_list|. 188 void HandleSelectiveAck(const PersistentIdList& id_list); 189 // Handle server confirmation of a device message, including device's 190 // acknowledgment of receipt of messages. 191 void HandleServerConfirmedReceipt(StreamId device_stream_id); 192 193 // Generates a new persistent id for messages. 194 // Virtual for testing. 195 virtual PersistentId GetNextPersistentId(); 196 197 // Helper for the heartbeat manager to signal a connection reset. 198 void OnConnectionResetByHeartbeat(); 199 200 // Runs the message_sent_callback_ with send |status| of the |protobuf|. 201 void NotifyMessageSendStatus(const google::protobuf::MessageLite& protobuf, 202 MessageSendStatus status); 203 204 // Pops the next message from the front of the send queue (cleaning up 205 // any associated state). 206 MCSPacketInternal PopMessageForSend(); 207 208 // Local version string. Sent on login. 209 const std::string version_string_; 210 211 // Clock for enforcing TTL. Passed in for testing. 212 base::Clock* const clock_; 213 214 // Client state. 215 State state_; 216 217 // Callbacks for owner. 218 ErrorCallback mcs_error_callback_; 219 OnMessageReceivedCallback message_received_callback_; 220 OnMessageSentCallback message_sent_callback_; 221 222 // The android id and security token in use by this device. 223 uint64 android_id_; 224 uint64 security_token_; 225 226 // Factory for creating new connections and connection handlers. 227 ConnectionFactory* connection_factory_; 228 229 // Connection handler to handle all over-the-wire protocol communication 230 // with the mobile connection server. 231 ConnectionHandler* connection_handler_; 232 233 // ----- Reliablie Message Queue section ----- 234 // Note: all queues/maps are ordered from oldest (front/begin) message to 235 // most recent (back/end). 236 237 // Send/acknowledge queues. 238 std::deque<MCSPacketInternal> to_send_; 239 std::deque<MCSPacketInternal> to_resend_; 240 241 // Map of collapse keys to their pending messages. 242 std::map<CollapseKey, ReliablePacketInfo*> collapse_key_map_; 243 244 // Last device_to_server stream id acknowledged by the server. 245 StreamId last_device_to_server_stream_id_received_; 246 // Last server_to_device stream id acknowledged by this device. 247 StreamId last_server_to_device_stream_id_received_; 248 // The stream id for the last sent message. A new message should consume 249 // stream_id_out_ + 1. 250 StreamId stream_id_out_; 251 // The stream id of the last received message. The LoginResponse will always 252 // have a stream id of 1, and stream ids increment by 1 for each received 253 // message. 254 StreamId stream_id_in_; 255 256 // The server messages that have not been acked by the device yet. Keyed by 257 // server stream id. 258 StreamIdToPersistentIdMap unacked_server_ids_; 259 260 // Those server messages that have been acked. They must remain tracked 261 // until the ack message is itself confirmed. The list of all message ids 262 // acknowledged are keyed off the device stream id of the message that 263 // acknowledged them. 264 std::map<StreamId, PersistentIdList> acked_server_ids_; 265 266 // Those server messages from a previous connection that were not fully 267 // acknowledged. They do not have associated stream ids, and will be 268 // acknowledged on the next login attempt. 269 PersistentIdList restored_unackeds_server_ids_; 270 271 // The GCM persistent store. Not owned. 272 GCMStore* gcm_store_; 273 274 // Manager to handle triggering/detecting heartbeats. 275 HeartbeatManager heartbeat_manager_; 276 277 // Recorder that records GCM activities for debugging purpose. Not owned. 278 GCMStatsRecorder* recorder_; 279 280 base::WeakPtrFactory<MCSClient> weak_ptr_factory_; 281 282 DISALLOW_COPY_AND_ASSIGN(MCSClient); 283 }; 284 285 } // namespace gcm 286 287 #endif // GOOGLE_APIS_GCM_ENGINE_MCS_CLIENT_H_ 288