Home | History | Annotate | Download | only in engine
      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.
    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