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/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"
29 } // namespace protobuf
38 class ConnectionFactory;
39 struct ReliablePacketInfo;
41 // An MCS client. This client is in charge of all communications with an
42 // MCS endpoint, and is capable of reliably sending/receiving GCM messages.
43 // NOTE: Not thread safe. This class should live on the same thread as that
44 // network requests are performed on.
45 class GCM_EXPORT MCSClient {
48 UNINITIALIZED, // Uninitialized.
49 LOADED, // GCM Load finished, waiting to connect.
50 CONNECTING, // Connection in progress.
51 CONNECTED, // Connected and running.
54 enum MessageSendStatus {
55 // Message sent succcessfully.
57 // Message not saved, because total queue size limit reached.
58 QUEUE_SIZE_LIMIT_REACHED,
59 // Messgae not saved, because app queue size limit reached.
60 APP_QUEUE_SIZE_LIMIT_REACHED,
61 // Message too large to send.
63 // Message not send becuase of TTL = 0 and no working connection.
64 NO_CONNECTION_ON_ZERO_TTL,
65 // Message exceeded TTL.
69 // Callback for MCSClient's error conditions.
70 // TODO(fgorski): Keeping it as a callback with intention to add meaningful
72 typedef base::Callback<void()> ErrorCallback;
73 // Callback when a message is received.
74 typedef base::Callback<void(const MCSMessage& message)>
75 OnMessageReceivedCallback;
76 // Callback when a message is sent (and receipt has been acknowledged by
78 typedef base::Callback<
79 void(int64 user_serial_number,
80 const std::string& app_id,
81 const std::string& message_id,
82 MessageSendStatus status)> OnMessageSentCallback;
84 MCSClient(base::Clock* clock,
85 ConnectionFactory* connection_factory,
89 // Initialize the client. Will load any previous id/token information as well
90 // as unacknowledged message information from the GCM storage, if it exists,
91 // passing the id/token information back via |initialization_callback| along
92 // with a |success == true| result. If no GCM information is present (and
93 // this is therefore a fresh client), a clean GCM store will be created and
94 // values of 0 will be returned via |initialization_callback| with
96 /// If an error loading the GCM store is encountered,
97 // |initialization_callback| will be invoked with |success == false|.
98 void Initialize(const ErrorCallback& initialization_callback,
99 const OnMessageReceivedCallback& message_received_callback,
100 const OnMessageSentCallback& message_sent_callback,
101 scoped_ptr<GCMStore::LoadResult> load_result);
103 // Logs the client into the server. Client must be initialized.
104 // |android_id| and |security_token| are optional if this is not a new
105 // client, else they must be non-zero.
106 // Successful login will result in |message_received_callback| being invoked
107 // with a valid LoginResponse.
108 // Login failure (typically invalid id/token) will shut down the client, and
109 // |initialization_callback| to be invoked with |success = false|.
110 void Login(uint64 android_id, uint64 security_token);
112 // Sends a message, with or without reliable message queueing (RMQ) support.
113 // Will asynchronously invoke the OnMessageSent callback regardless.
114 // Whether to use RMQ depends on whether the protobuf has |ttl| set or not.
115 // |ttl == 0| denotes the message should only be sent if the connection is
116 // open. |ttl > 0| will keep the message saved for |ttl| seconds, after which
117 // it will be dropped if it was unable to be sent. When a message is dropped,
118 // |message_sent_callback_| is invoked with a TTL expiration error.
119 void SendMessage(const MCSMessage& message);
121 // Disconnects the client and permanently destroys the persistent GCM store.
122 // WARNING: This is permanent, and the client must be recreated with new
123 // credentials afterwards.
126 // Returns the current state of the client.
127 State state() const { return state_; }
130 typedef uint32 StreamId;
131 typedef std::string PersistentId;
132 typedef std::vector<StreamId> StreamIdList;
133 typedef std::vector<PersistentId> PersistentIdList;
134 typedef std::map<StreamId, PersistentId> StreamIdToPersistentIdMap;
135 typedef linked_ptr<ReliablePacketInfo> MCSPacketInternal;
137 // Resets the internal state and builds a new login request, acknowledging
138 // any pending server-to-device messages and rebuilding the send queue
139 // from all unacknowledged device-to-server messages.
140 // Should only be called when the connection has been reset.
141 void ResetStateAndBuildLoginRequest(mcs_proto::LoginRequest* request);
143 // Send a heartbeat to the MCS server.
144 void SendHeartbeat();
146 // GCM Store callback.
147 void OnGCMUpdateFinished(bool success);
149 // Attempt to send a message.
150 void MaybeSendMessage();
152 // Helper for sending a protobuf along with any unacknowledged ids to the
154 void SendPacketToWire(ReliablePacketInfo* packet_info);
156 // Handle a data message sent to the MCS client system from the MCS server.
157 void HandleMCSDataMesssage(
158 scoped_ptr<google::protobuf::MessageLite> protobuf);
160 // Handle a packet received over the wire.
161 void HandlePacketFromWire(scoped_ptr<google::protobuf::MessageLite> protobuf);
163 // ReliableMessageQueue acknowledgment helpers.
164 // Handle a StreamAck sent by the server confirming receipt of all
165 // messages up to the message with stream id |last_stream_id_received|.
166 void HandleStreamAck(StreamId last_stream_id_received_);
167 // Handle a SelectiveAck sent by the server confirming all messages
169 void HandleSelectiveAck(const PersistentIdList& id_list);
170 // Handle server confirmation of a device message, including device's
171 // acknowledgment of receipt of messages.
172 void HandleServerConfirmedReceipt(StreamId device_stream_id);
174 // Generates a new persistent id for messages.
175 // Virtual for testing.
176 virtual PersistentId GetNextPersistentId();
178 // Helper for the heartbeat manager to signal a connection reset.
179 void OnConnectionResetByHeartbeat();
181 // Runs the message_sent_callback_ with send |status| of the |protobuf|.
182 void NotifyMessageSendStatus(const google::protobuf::MessageLite& protobuf,
183 MessageSendStatus status);
185 // Clock for enforcing TTL. Passed in for testing.
186 base::Clock* const clock_;
191 // Callbacks for owner.
192 ErrorCallback mcs_error_callback_;
193 OnMessageReceivedCallback message_received_callback_;
194 OnMessageSentCallback message_sent_callback_;
196 // The android id and security token in use by this device.
198 uint64 security_token_;
200 // Factory for creating new connections and connection handlers.
201 ConnectionFactory* connection_factory_;
203 // Connection handler to handle all over-the-wire protocol communication
204 // with the mobile connection server.
205 ConnectionHandler* connection_handler_;
207 // ----- Reliablie Message Queue section -----
208 // Note: all queues/maps are ordered from oldest (front/begin) message to
209 // most recent (back/end).
211 // Send/acknowledge queues.
212 std::deque<MCSPacketInternal> to_send_;
213 std::deque<MCSPacketInternal> to_resend_;
215 // Last device_to_server stream id acknowledged by the server.
216 StreamId last_device_to_server_stream_id_received_;
217 // Last server_to_device stream id acknowledged by this device.
218 StreamId last_server_to_device_stream_id_received_;
219 // The stream id for the last sent message. A new message should consume
220 // stream_id_out_ + 1.
221 StreamId stream_id_out_;
222 // The stream id of the last received message. The LoginResponse will always
223 // have a stream id of 1, and stream ids increment by 1 for each received
225 StreamId stream_id_in_;
227 // The server messages that have not been acked by the device yet. Keyed by
229 StreamIdToPersistentIdMap unacked_server_ids_;
231 // Those server messages that have been acked. They must remain tracked
232 // until the ack message is itself confirmed. The list of all message ids
233 // acknowledged are keyed off the device stream id of the message that
234 // acknowledged them.
235 std::map<StreamId, PersistentIdList> acked_server_ids_;
237 // Those server messages from a previous connection that were not fully
238 // acknowledged. They do not have associated stream ids, and will be
239 // acknowledged on the next login attempt.
240 PersistentIdList restored_unackeds_server_ids_;
242 // The GCM persistent store. Not owned.
243 GCMStore* gcm_store_;
245 // Manager to handle triggering/detecting heartbeats.
246 HeartbeatManager heartbeat_manager_;
248 base::WeakPtrFactory<MCSClient> weak_ptr_factory_;
250 DISALLOW_COPY_AND_ASSIGN(MCSClient);
255 #endif // GOOGLE_APIS_GCM_ENGINE_MCS_CLIENT_H_