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