mcs_probe.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  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. // A standalone tool for testing MCS connections and the MCS client on their
  6. // own.
  7. #include <stdint.h>
  8. #include <cstddef>
  9. #include <cstdio>
  10. #include <memory>
  11. #include <set>
  12. #include <string>
  13. #include <utility>
  14. #include <vector>
  15. #include "base/at_exit.h"
  16. #include "base/bind.h"
  17. #include "base/callback.h"
  18. #include "base/command_line.h"
  19. #include "base/compiler_specific.h"
  20. #include "base/files/scoped_file.h"
  21. #include "base/logging.h"
  22. #include "base/memory/ptr_util.h"
  23. #include "base/memory/ref_counted.h"
  24. #include "base/message_loop/message_pump_type.h"
  25. #include "base/run_loop.h"
  26. #include "base/strings/string_number_conversions.h"
  27. #include "base/task/single_thread_task_executor.h"
  28. #include "base/task/thread_pool/thread_pool_instance.h"
  29. #include "base/threading/thread.h"
  30. #include "base/threading/thread_task_runner_handle.h"
  31. #include "base/time/default_clock.h"
  32. #include "base/time/time.h"
  33. #include "base/values.h"
  34. #include "build/build_config.h"
  35. #include "google_apis/gcm/base/fake_encryptor.h"
  36. #include "google_apis/gcm/base/mcs_message.h"
  37. #include "google_apis/gcm/base/mcs_util.h"
  38. #include "google_apis/gcm/engine/checkin_request.h"
  39. #include "google_apis/gcm/engine/connection_factory_impl.h"
  40. #include "google_apis/gcm/engine/gcm_store_impl.h"
  41. #include "google_apis/gcm/engine/gservices_settings.h"
  42. #include "google_apis/gcm/engine/mcs_client.h"
  43. #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
  44. #include "mojo/core/embedder/embedder.h"
  45. #include "mojo/public/cpp/bindings/pending_receiver.h"
  46. #include "mojo/public/cpp/bindings/remote.h"
  47. #include "net/cert/cert_verifier.h"
  48. #include "net/dns/host_resolver.h"
  49. #include "net/http/http_auth_handler_factory.h"
  50. #include "net/http/http_auth_preferences.h"
  51. #include "net/http/http_auth_scheme.h"
  52. #include "net/log/file_net_log_observer.h"
  53. #include "net/proxy_resolution/configured_proxy_resolution_service.h"
  54. #include "net/url_request/url_request_context.h"
  55. #include "net/url_request/url_request_context_builder.h"
  56. #include "net/url_request/url_request_test_util.h"
  57. #include "services/network/network_context.h"
  58. #include "services/network/public/cpp/shared_url_loader_factory.h"
  59. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  60. #include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
  61. #include "services/network/public/mojom/url_loader_factory.mojom.h"
  62. #include "services/network/test/test_network_connection_tracker.h"
  63. #include "url/scheme_host_port.h"
  64. #if BUILDFLAG(IS_MAC)
  65. #include "base/mac/scoped_nsautorelease_pool.h"
  66. #endif
  67. // This is a simple utility that initializes an mcs client and
  68. // prints out any events.
  69. namespace gcm {
  70. namespace {
  71. const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
  72. // Number of initial errors (in sequence) to ignore before applying
  73. // exponential back-off rules.
  74. 0,
  75. // Initial delay for exponential back-off in ms.
  76. 15000, // 15 seconds.
  77. // Factor by which the waiting time will be multiplied.
  78. 2,
  79. // Fuzzing percentage. ex: 10% will spread requests randomly
  80. // between 90%-100% of the calculated time.
  81. 0.5, // 50%.
  82. // Maximum amount of time we are willing to delay our request in ms.
  83. 1000 * 60 * 5, // 5 minutes.
  84. // Time to keep an entry from being discarded even when it
  85. // has no significant state, -1 to never discard.
  86. -1,
  87. // Don't use initial delay unless the last request was an error.
  88. false,
  89. };
  90. // Default values used to communicate with the check-in server.
  91. const char kChromeVersion[] = "Chrome MCS Probe";
  92. // The default server to communicate with.
  93. const char kMCSServerHost[] = "mtalk.google.com";
  94. const uint16_t kMCSServerPort = 5228;
  95. // Command line switches.
  96. const char kRMQFileName[] = "rmq_file";
  97. const char kAndroidIdSwitch[] = "android_id";
  98. const char kSecretSwitch[] = "secret";
  99. const char kLogFileSwitch[] = "log-file";
  100. const char kIgnoreCertSwitch[] = "ignore-certs";
  101. const char kServerHostSwitch[] = "host";
  102. const char kServerPortSwitch[] = "port";
  103. void MessageReceivedCallback(const MCSMessage& message) {
  104. LOG(INFO) << "Received message with id "
  105. << GetPersistentId(message.GetProtobuf()) << " and tag "
  106. << static_cast<int>(message.tag());
  107. if (message.tag() == kDataMessageStanzaTag) {
  108. const mcs_proto::DataMessageStanza& data_message =
  109. reinterpret_cast<const mcs_proto::DataMessageStanza&>(
  110. message.GetProtobuf());
  111. DVLOG(1) << " to: " << data_message.to();
  112. DVLOG(1) << " from: " << data_message.from();
  113. DVLOG(1) << " category: " << data_message.category();
  114. DVLOG(1) << " sent: " << data_message.sent();
  115. for (int i = 0; i < data_message.app_data_size(); ++i) {
  116. DVLOG(1) << " App data " << i << " "
  117. << data_message.app_data(i).key() << " : "
  118. << data_message.app_data(i).value();
  119. }
  120. }
  121. }
  122. void MessageSentCallback(int64_t user_serial_number,
  123. const std::string& app_id,
  124. const std::string& message_id,
  125. MCSClient::MessageSendStatus status) {
  126. LOG(INFO) << "Message sent. Serial number: " << user_serial_number
  127. << " Application ID: " << app_id
  128. << " Message ID: " << message_id
  129. << " Message send status: " << status;
  130. }
  131. // A cert verifier that access all certificates.
  132. class MyTestCertVerifier : public net::CertVerifier {
  133. public:
  134. MyTestCertVerifier() {}
  135. ~MyTestCertVerifier() override {}
  136. int Verify(const RequestParams& params,
  137. net::CertVerifyResult* verify_result,
  138. net::CompletionOnceCallback callback,
  139. std::unique_ptr<Request>* out_req,
  140. const net::NetLogWithSource& net_log) override {
  141. verify_result->Reset();
  142. verify_result->verified_cert = params.certificate();
  143. return net::OK;
  144. }
  145. void SetConfig(const Config& config) override {}
  146. };
  147. class MCSProbeAuthPreferences : public net::HttpAuthPreferences {
  148. public:
  149. MCSProbeAuthPreferences() {}
  150. ~MCSProbeAuthPreferences() override {}
  151. bool NegotiateDisableCnameLookup() const override { return false; }
  152. bool NegotiateEnablePort() const override { return false; }
  153. bool CanUseDefaultCredentials(
  154. const url::SchemeHostPort& auth_scheme_host_port) const override {
  155. return false;
  156. }
  157. net::HttpAuth::DelegationType GetDelegationType(
  158. const url::SchemeHostPort& auth_scheme_host_port) const override {
  159. return net::HttpAuth::DelegationType::kNone;
  160. }
  161. };
  162. class MCSProbe {
  163. public:
  164. explicit MCSProbe(const base::CommandLine& command_line);
  165. ~MCSProbe();
  166. void Start();
  167. uint64_t android_id() const { return android_id_; }
  168. uint64_t secret() const { return secret_; }
  169. private:
  170. void RequestProxyResolvingSocketFactory(
  171. mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
  172. receiver);
  173. void CheckIn();
  174. void InitializeNetworkState();
  175. void LoadCallback(std::unique_ptr<GCMStore::LoadResult> load_result);
  176. void UpdateCallback(bool success);
  177. void ErrorCallback();
  178. void OnCheckInCompleted(
  179. net::HttpStatusCode response_code,
  180. const checkin_proto::AndroidCheckinResponse& checkin_response);
  181. void StartMCSLogin();
  182. base::DefaultClock clock_;
  183. base::CommandLine command_line_;
  184. base::FilePath gcm_store_path_;
  185. uint64_t android_id_;
  186. uint64_t secret_;
  187. std::string server_host_;
  188. int server_port_;
  189. // Network state.
  190. std::unique_ptr<network::TestNetworkConnectionTracker>
  191. network_connection_tracker_;
  192. std::unique_ptr<net::URLRequestContext> url_request_context_;
  193. net::NetLog* net_log_;
  194. std::unique_ptr<net::FileNetLogObserver> logger_;
  195. MCSProbeAuthPreferences http_auth_preferences_;
  196. FakeGCMStatsRecorder recorder_;
  197. std::unique_ptr<GCMStore> gcm_store_;
  198. std::unique_ptr<MCSClient> mcs_client_;
  199. std::unique_ptr<CheckinRequest> checkin_request_;
  200. std::unique_ptr<ConnectionFactoryImpl> connection_factory_;
  201. base::Thread file_thread_;
  202. std::unique_ptr<network::NetworkContext> network_context_;
  203. mojo::Remote<network::mojom::NetworkContext> network_context_remote_;
  204. mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
  205. scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
  206. std::unique_ptr<base::RunLoop> run_loop_;
  207. };
  208. MCSProbe::MCSProbe(const base::CommandLine& command_line)
  209. : command_line_(command_line),
  210. gcm_store_path_(base::FilePath(FILE_PATH_LITERAL("gcm_store"))),
  211. android_id_(0),
  212. secret_(0),
  213. server_port_(0),
  214. network_connection_tracker_(
  215. network::TestNetworkConnectionTracker::CreateInstance()),
  216. net_log_(net::NetLog::Get()),
  217. file_thread_("FileThread") {
  218. network_connection_tracker_->SetConnectionType(
  219. network::mojom::ConnectionType::CONNECTION_ETHERNET);
  220. if (command_line.HasSwitch(kRMQFileName)) {
  221. gcm_store_path_ = command_line.GetSwitchValuePath(kRMQFileName);
  222. }
  223. if (command_line.HasSwitch(kAndroidIdSwitch)) {
  224. base::StringToUint64(command_line.GetSwitchValueASCII(kAndroidIdSwitch),
  225. &android_id_);
  226. }
  227. if (command_line.HasSwitch(kSecretSwitch)) {
  228. base::StringToUint64(command_line.GetSwitchValueASCII(kSecretSwitch),
  229. &secret_);
  230. }
  231. server_host_ = kMCSServerHost;
  232. if (command_line.HasSwitch(kServerHostSwitch)) {
  233. server_host_ = command_line.GetSwitchValueASCII(kServerHostSwitch);
  234. }
  235. server_port_ = kMCSServerPort;
  236. if (command_line.HasSwitch(kServerPortSwitch)) {
  237. base::StringToInt(command_line.GetSwitchValueASCII(kServerPortSwitch),
  238. &server_port_);
  239. }
  240. }
  241. MCSProbe::~MCSProbe() {
  242. if (logger_)
  243. logger_->StopObserving(nullptr, base::OnceClosure());
  244. file_thread_.Stop();
  245. }
  246. void MCSProbe::Start() {
  247. file_thread_.Start();
  248. InitializeNetworkState();
  249. std::vector<GURL> endpoints(
  250. 1, GURL("https://" +
  251. net::HostPortPair(server_host_, server_port_).ToString()));
  252. connection_factory_ = std::make_unique<ConnectionFactoryImpl>(
  253. endpoints, kDefaultBackoffPolicy,
  254. base::BindRepeating(&MCSProbe::RequestProxyResolvingSocketFactory,
  255. base::Unretained(this)),
  256. base::ThreadTaskRunnerHandle::Get(), &recorder_,
  257. network_connection_tracker_.get());
  258. gcm_store_ = std::make_unique<GCMStoreImpl>(
  259. gcm_store_path_, /*remove_account_mappings_with_email_key=*/true,
  260. file_thread_.task_runner(), std::make_unique<FakeEncryptor>());
  261. mcs_client_ = std::make_unique<MCSClient>(
  262. "probe", &clock_, connection_factory_.get(), gcm_store_.get(),
  263. base::ThreadTaskRunnerHandle::Get(), &recorder_);
  264. run_loop_ = std::make_unique<base::RunLoop>();
  265. gcm_store_->Load(
  266. GCMStore::CREATE_IF_MISSING,
  267. base::BindOnce(&MCSProbe::LoadCallback, base::Unretained(this)));
  268. run_loop_->Run();
  269. }
  270. void MCSProbe::LoadCallback(std::unique_ptr<GCMStore::LoadResult> load_result) {
  271. DCHECK(load_result->success);
  272. if (android_id_ != 0 && secret_ != 0) {
  273. DVLOG(1) << "Presetting MCS id " << android_id_;
  274. load_result->device_android_id = android_id_;
  275. load_result->device_security_token = secret_;
  276. gcm_store_->SetDeviceCredentials(
  277. android_id_, secret_,
  278. base::BindOnce(&MCSProbe::UpdateCallback, base::Unretained(this)));
  279. } else {
  280. android_id_ = load_result->device_android_id;
  281. secret_ = load_result->device_security_token;
  282. DVLOG(1) << "Loaded MCS id " << android_id_;
  283. }
  284. mcs_client_->Initialize(
  285. base::BindRepeating(&MCSProbe::ErrorCallback, base::Unretained(this)),
  286. base::BindRepeating(&MessageReceivedCallback),
  287. base::BindRepeating(&MessageSentCallback), std::move(load_result));
  288. if (!android_id_ || !secret_) {
  289. DVLOG(1) << "Checkin to generate new MCS credentials.";
  290. CheckIn();
  291. return;
  292. }
  293. StartMCSLogin();
  294. }
  295. void MCSProbe::UpdateCallback(bool success) {
  296. }
  297. void MCSProbe::InitializeNetworkState() {
  298. if (command_line_.HasSwitch(kLogFileSwitch)) {
  299. base::FilePath log_path = command_line_.GetSwitchValuePath(kLogFileSwitch);
  300. net::NetLogCaptureMode capture_mode =
  301. net::NetLogCaptureMode::kIncludeSensitive;
  302. logger_ = net::FileNetLogObserver::CreateUnbounded(log_path, capture_mode,
  303. nullptr);
  304. logger_->StartObserving(net_log_);
  305. }
  306. net::URLRequestContextBuilder builder;
  307. builder.set_net_log(net_log_);
  308. builder.set_host_resolver(
  309. net::HostResolver::CreateStandaloneResolver(net_log_));
  310. http_auth_preferences_.set_allowed_schemes(
  311. std::set<std::string>{net::kBasicAuthScheme});
  312. builder.SetHttpAuthHandlerFactory(
  313. net::HttpAuthHandlerRegistryFactory::Create(&http_auth_preferences_));
  314. builder.set_proxy_resolution_service(
  315. net::ConfiguredProxyResolutionService::CreateDirect());
  316. if (command_line_.HasSwitch(kIgnoreCertSwitch))
  317. builder.SetCertVerifier(std::make_unique<MyTestCertVerifier>());
  318. url_request_context_ = builder.Build();
  319. // Wrap it up with network service APIs.
  320. network_context_ = std::make_unique<network::NetworkContext>(
  321. nullptr /* network_service */,
  322. network_context_remote_.BindNewPipeAndPassReceiver(),
  323. url_request_context_.get(),
  324. /*cors_exempt_header_list=*/std::vector<std::string>());
  325. auto url_loader_factory_params =
  326. network::mojom::URLLoaderFactoryParams::New();
  327. url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
  328. url_loader_factory_params->is_corb_enabled = false;
  329. network_context_->CreateURLLoaderFactory(
  330. url_loader_factory_.BindNewPipeAndPassReceiver(),
  331. std::move(url_loader_factory_params));
  332. shared_url_loader_factory_ =
  333. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  334. url_loader_factory_.get());
  335. }
  336. void MCSProbe::ErrorCallback() {
  337. LOG(INFO) << "MCS error happened";
  338. }
  339. void MCSProbe::RequestProxyResolvingSocketFactory(
  340. mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
  341. receiver) {
  342. return network_context_->CreateProxyResolvingSocketFactory(
  343. std::move(receiver));
  344. }
  345. void MCSProbe::CheckIn() {
  346. LOG(INFO) << "Check-in request initiated.";
  347. checkin_proto::ChromeBuildProto chrome_build_proto;
  348. chrome_build_proto.set_platform(
  349. checkin_proto::ChromeBuildProto::PLATFORM_LINUX);
  350. chrome_build_proto.set_channel(
  351. checkin_proto::ChromeBuildProto::CHANNEL_CANARY);
  352. chrome_build_proto.set_chrome_version(kChromeVersion);
  353. CheckinRequest::RequestInfo request_info(0, 0,
  354. std::map<std::string, std::string>(),
  355. std::string(), chrome_build_proto);
  356. checkin_request_ = std::make_unique<CheckinRequest>(
  357. GServicesSettings().GetCheckinURL(), request_info, kDefaultBackoffPolicy,
  358. base::BindOnce(&MCSProbe::OnCheckInCompleted, base::Unretained(this)),
  359. shared_url_loader_factory_, base::ThreadTaskRunnerHandle::Get(),
  360. &recorder_);
  361. checkin_request_->Start();
  362. }
  363. void MCSProbe::OnCheckInCompleted(
  364. net::HttpStatusCode response_code,
  365. const checkin_proto::AndroidCheckinResponse& checkin_response) {
  366. bool success = response_code == net::HTTP_OK &&
  367. checkin_response.has_android_id() &&
  368. checkin_response.android_id() != 0UL &&
  369. checkin_response.has_security_token() &&
  370. checkin_response.security_token() != 0UL;
  371. LOG(INFO) << "Check-in request completion "
  372. << (success ? "success!" : "failure!");
  373. if (!success)
  374. return;
  375. android_id_ = checkin_response.android_id();
  376. secret_ = checkin_response.security_token();
  377. gcm_store_->SetDeviceCredentials(
  378. android_id_, secret_,
  379. base::BindOnce(&MCSProbe::UpdateCallback, base::Unretained(this)));
  380. StartMCSLogin();
  381. }
  382. void MCSProbe::StartMCSLogin() {
  383. LOG(INFO) << "MCS login initiated.";
  384. mcs_client_->Login(android_id_, secret_);
  385. }
  386. int MCSProbeMain(int argc, char* argv[]) {
  387. base::AtExitManager exit_manager;
  388. base::CommandLine::Init(argc, argv);
  389. logging::LoggingSettings settings;
  390. settings.logging_dest =
  391. logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
  392. logging::InitLogging(settings);
  393. mojo::core::Init();
  394. base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
  395. base::ThreadPoolInstance::CreateAndStartWithDefaultParams("MCSProbe");
  396. const base::CommandLine& command_line =
  397. *base::CommandLine::ForCurrentProcess();
  398. MCSProbe mcs_probe(command_line);
  399. mcs_probe.Start();
  400. base::RunLoop run_loop;
  401. run_loop.Run();
  402. base::ThreadPoolInstance::Get()->Shutdown();
  403. return 0;
  404. }
  405. } // namespace
  406. } // namespace gcm
  407. int main(int argc, char* argv[]) {
  408. return gcm::MCSProbeMain(argc, argv);
  409. }