Home | History | Annotate | Download | only in base
      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 #include "google_apis/gcm/base/mcs_util.h"
      6 
      7 #include "base/format_macros.h"
      8 #include "base/logging.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "base/strings/stringprintf.h"
     11 
     12 namespace gcm {
     13 
     14 namespace {
     15 
     16 // Type names corresponding to MCSProtoTags. Useful for identifying what type
     17 // of MCS protobuf is contained within a google::protobuf::MessageLite object.
     18 // WARNING: must match the order in MCSProtoTag.
     19 const char* kProtoNames[] = {
     20   "mcs_proto.HeartbeatPing",
     21   "mcs_proto.HeartbeatAck",
     22   "mcs_proto.LoginRequest",
     23   "mcs_proto.LoginResponse",
     24   "mcs_proto.Close",
     25   "mcs_proto.MessageStanza",
     26   "mcs_proto.PresenceStanza",
     27   "mcs_proto.IqStanza",
     28   "mcs_proto.DataMessageStanza",
     29   "mcs_proto.BatchPresenceStanza",
     30   "mcs_proto.StreamErrorStanza",
     31   "mcs_proto.HttpRequest",
     32   "mcs_proto.HttpResponse",
     33   "mcs_proto.BindAccountRequest",
     34   "mcs_proto.BindAccountResponse",
     35   "mcs_proto.TalkMetadata"
     36 };
     37 COMPILE_ASSERT(arraysize(kProtoNames) == kNumProtoTypes,
     38                ProtoNamesMustIncludeAllTags);
     39 
     40 // TODO(zea): replace these with proper values.
     41 const char kLoginId[] = "login-1";
     42 const char kLoginDomain[] = "mcs.android.com";
     43 const char kLoginDeviceIdPrefix[] = "android-";
     44 const char kLoginSettingName[] = "new_vc";
     45 const char kLoginSettingValue[] = "1";
     46 
     47 }  // namespace
     48 
     49 scoped_ptr<mcs_proto::LoginRequest> BuildLoginRequest(uint64 auth_id,
     50                                                       uint64 auth_token) {
     51   // Create a hex encoded auth id for the device id field.
     52   std::string auth_id_hex;
     53   auth_id_hex = base::StringPrintf("%" PRIx64, auth_id);
     54 
     55   std::string auth_id_str = base::Uint64ToString(auth_id);
     56   std::string auth_token_str = base::Uint64ToString(auth_token);
     57 
     58   scoped_ptr<mcs_proto::LoginRequest> login_request(
     59       new mcs_proto::LoginRequest());
     60 
     61   // TODO(zea): set better values.
     62   login_request->set_account_id(1000000);
     63   login_request->set_adaptive_heartbeat(false);
     64   login_request->set_auth_service(mcs_proto::LoginRequest::ANDROID_ID);
     65   login_request->set_auth_token(auth_token_str);
     66   login_request->set_id(kLoginId);
     67   login_request->set_domain(kLoginDomain);
     68   login_request->set_device_id(kLoginDeviceIdPrefix + auth_id_hex);
     69   login_request->set_network_type(1);
     70   login_request->set_resource(auth_id_str);
     71   login_request->set_user(auth_id_str);
     72   login_request->set_use_rmq2(true);
     73 
     74   login_request->add_setting();
     75   login_request->mutable_setting(0)->set_name(kLoginSettingName);
     76   login_request->mutable_setting(0)->set_value(kLoginSettingValue);
     77   return login_request.Pass();
     78 }
     79 
     80 scoped_ptr<mcs_proto::IqStanza> BuildStreamAck() {
     81   scoped_ptr<mcs_proto::IqStanza> stream_ack_iq(new mcs_proto::IqStanza());
     82   stream_ack_iq->set_type(mcs_proto::IqStanza::SET);
     83   stream_ack_iq->set_id("");
     84   stream_ack_iq->mutable_extension()->set_id(kStreamAck);
     85   stream_ack_iq->mutable_extension()->set_data("");
     86   return stream_ack_iq.Pass();
     87 }
     88 
     89 scoped_ptr<mcs_proto::IqStanza> BuildSelectiveAck(
     90     const std::vector<std::string>& acked_ids) {
     91   scoped_ptr<mcs_proto::IqStanza> selective_ack_iq(new mcs_proto::IqStanza());
     92   selective_ack_iq->set_type(mcs_proto::IqStanza::SET);
     93   selective_ack_iq->set_id("");
     94   selective_ack_iq->mutable_extension()->set_id(kSelectiveAck);
     95   mcs_proto::SelectiveAck selective_ack;
     96   for (size_t i = 0; i < acked_ids.size(); ++i)
     97     selective_ack.add_id(acked_ids[i]);
     98   selective_ack_iq->mutable_extension()->set_data(
     99       selective_ack.SerializeAsString());
    100   return selective_ack_iq.Pass();
    101 }
    102 
    103 // Utility method to build a google::protobuf::MessageLite object from a MCS
    104 // tag.
    105 scoped_ptr<google::protobuf::MessageLite> BuildProtobufFromTag(uint8 tag) {
    106   switch(tag) {
    107     case kHeartbeatPingTag:
    108       return scoped_ptr<google::protobuf::MessageLite>(
    109           new mcs_proto::HeartbeatPing());
    110     case kHeartbeatAckTag:
    111       return scoped_ptr<google::protobuf::MessageLite>(
    112           new mcs_proto::HeartbeatAck());
    113     case kLoginRequestTag:
    114       return scoped_ptr<google::protobuf::MessageLite>(
    115           new mcs_proto::LoginRequest());
    116     case kLoginResponseTag:
    117       return scoped_ptr<google::protobuf::MessageLite>(
    118           new mcs_proto::LoginResponse());
    119     case kCloseTag:
    120       return scoped_ptr<google::protobuf::MessageLite>(
    121           new mcs_proto::Close());
    122     case kIqStanzaTag:
    123       return scoped_ptr<google::protobuf::MessageLite>(
    124           new mcs_proto::IqStanza());
    125     case kDataMessageStanzaTag:
    126       return scoped_ptr<google::protobuf::MessageLite>(
    127           new mcs_proto::DataMessageStanza());
    128     case kStreamErrorStanzaTag:
    129       return scoped_ptr<google::protobuf::MessageLite>(
    130           new mcs_proto::StreamErrorStanza());
    131     default:
    132       return scoped_ptr<google::protobuf::MessageLite>();
    133   }
    134 }
    135 
    136 // Utility method to extract a MCS tag from a google::protobuf::MessageLite
    137 // object.
    138 int GetMCSProtoTag(const google::protobuf::MessageLite& message) {
    139   const std::string& type_name = message.GetTypeName();
    140   if (type_name == kProtoNames[kHeartbeatPingTag]) {
    141     return kHeartbeatPingTag;
    142   } else if (type_name == kProtoNames[kHeartbeatAckTag]) {
    143     return kHeartbeatAckTag;
    144   } else if (type_name == kProtoNames[kLoginRequestTag]) {
    145     return kLoginRequestTag;
    146   } else if (type_name == kProtoNames[kLoginResponseTag]) {
    147     return kLoginResponseTag;
    148   } else if (type_name == kProtoNames[kCloseTag]) {
    149     return kCloseTag;
    150   } else if (type_name == kProtoNames[kIqStanzaTag]) {
    151     return kIqStanzaTag;
    152   } else if (type_name == kProtoNames[kDataMessageStanzaTag]) {
    153     return kDataMessageStanzaTag;
    154   } else if (type_name == kProtoNames[kStreamErrorStanzaTag]) {
    155     return kStreamErrorStanzaTag;
    156   }
    157   return -1;
    158 }
    159 
    160 std::string GetPersistentId(const google::protobuf::MessageLite& protobuf) {
    161   if (protobuf.GetTypeName() == kProtoNames[kIqStanzaTag]) {
    162     return reinterpret_cast<const mcs_proto::IqStanza*>(&protobuf)->
    163         persistent_id();
    164   } else if (protobuf.GetTypeName() == kProtoNames[kDataMessageStanzaTag]) {
    165     return reinterpret_cast<const mcs_proto::DataMessageStanza*>(&protobuf)->
    166         persistent_id();
    167   }
    168   // Not all message types have persistent ids. Just return empty string;
    169   return "";
    170 }
    171 
    172 void SetPersistentId(const std::string& persistent_id,
    173                      google::protobuf::MessageLite* protobuf) {
    174   if (protobuf->GetTypeName() == kProtoNames[kIqStanzaTag]) {
    175     reinterpret_cast<mcs_proto::IqStanza*>(protobuf)->
    176         set_persistent_id(persistent_id);
    177     return;
    178   } else if (protobuf->GetTypeName() == kProtoNames[kDataMessageStanzaTag]) {
    179     reinterpret_cast<mcs_proto::DataMessageStanza*>(protobuf)->
    180         set_persistent_id(persistent_id);
    181     return;
    182   }
    183   NOTREACHED();
    184 }
    185 
    186 uint32 GetLastStreamIdReceived(const google::protobuf::MessageLite& protobuf) {
    187   if (protobuf.GetTypeName() == kProtoNames[kIqStanzaTag]) {
    188     return reinterpret_cast<const mcs_proto::IqStanza*>(&protobuf)->
    189         last_stream_id_received();
    190   } else if (protobuf.GetTypeName() == kProtoNames[kDataMessageStanzaTag]) {
    191     return reinterpret_cast<const mcs_proto::DataMessageStanza*>(&protobuf)->
    192         last_stream_id_received();
    193   } else if (protobuf.GetTypeName() == kProtoNames[kHeartbeatPingTag]) {
    194     return reinterpret_cast<const mcs_proto::HeartbeatPing*>(&protobuf)->
    195         last_stream_id_received();
    196   } else if (protobuf.GetTypeName() == kProtoNames[kHeartbeatAckTag]) {
    197     return reinterpret_cast<const mcs_proto::HeartbeatAck*>(&protobuf)->
    198         last_stream_id_received();
    199   } else if (protobuf.GetTypeName() == kProtoNames[kLoginResponseTag]) {
    200     return reinterpret_cast<const mcs_proto::LoginResponse*>(&protobuf)->
    201         last_stream_id_received();
    202   }
    203   // Not all message types have last stream ids. Just return 0.
    204   return 0;
    205 }
    206 
    207 void SetLastStreamIdReceived(uint32 val,
    208                              google::protobuf::MessageLite* protobuf) {
    209   if (protobuf->GetTypeName() == kProtoNames[kIqStanzaTag]) {
    210     reinterpret_cast<mcs_proto::IqStanza*>(protobuf)->
    211         set_last_stream_id_received(val);
    212      return;
    213   } else if (protobuf->GetTypeName() == kProtoNames[kHeartbeatPingTag]) {
    214     reinterpret_cast<mcs_proto::HeartbeatPing*>(protobuf)->
    215         set_last_stream_id_received(val);
    216      return;
    217   } else if (protobuf->GetTypeName() == kProtoNames[kHeartbeatAckTag]) {
    218     reinterpret_cast<mcs_proto::HeartbeatAck*>(protobuf)->
    219         set_last_stream_id_received(val);
    220      return;
    221   } else if (protobuf->GetTypeName() == kProtoNames[kDataMessageStanzaTag]) {
    222     reinterpret_cast<mcs_proto::DataMessageStanza*>(protobuf)->
    223         set_last_stream_id_received(val);
    224      return;
    225   } else if (protobuf->GetTypeName() == kProtoNames[kLoginResponseTag]) {
    226     reinterpret_cast<mcs_proto::LoginResponse*>(protobuf)->
    227         set_last_stream_id_received(val);
    228      return;
    229   }
    230   NOTREACHED();
    231 }
    232 
    233 }  // namespace gcm
    234