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