123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- //
- // A standalone tool for testing MCS connections and the MCS client on their
- // own.
- #include <stdint.h>
- #include <cstddef>
- #include <cstdio>
- #include <memory>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/at_exit.h"
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/command_line.h"
- #include "base/compiler_specific.h"
- #include "base/files/scoped_file.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/ref_counted.h"
- #include "base/message_loop/message_pump_type.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/task/single_thread_task_executor.h"
- #include "base/task/thread_pool/thread_pool_instance.h"
- #include "base/threading/thread.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/default_clock.h"
- #include "base/time/time.h"
- #include "base/values.h"
- #include "build/build_config.h"
- #include "google_apis/gcm/base/fake_encryptor.h"
- #include "google_apis/gcm/base/mcs_message.h"
- #include "google_apis/gcm/base/mcs_util.h"
- #include "google_apis/gcm/engine/checkin_request.h"
- #include "google_apis/gcm/engine/connection_factory_impl.h"
- #include "google_apis/gcm/engine/gcm_store_impl.h"
- #include "google_apis/gcm/engine/gservices_settings.h"
- #include "google_apis/gcm/engine/mcs_client.h"
- #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
- #include "mojo/core/embedder/embedder.h"
- #include "mojo/public/cpp/bindings/pending_receiver.h"
- #include "mojo/public/cpp/bindings/remote.h"
- #include "net/cert/cert_verifier.h"
- #include "net/dns/host_resolver.h"
- #include "net/http/http_auth_handler_factory.h"
- #include "net/http/http_auth_preferences.h"
- #include "net/http/http_auth_scheme.h"
- #include "net/log/file_net_log_observer.h"
- #include "net/proxy_resolution/configured_proxy_resolution_service.h"
- #include "net/url_request/url_request_context.h"
- #include "net/url_request/url_request_context_builder.h"
- #include "net/url_request/url_request_test_util.h"
- #include "services/network/network_context.h"
- #include "services/network/public/cpp/shared_url_loader_factory.h"
- #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
- #include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
- #include "services/network/public/mojom/url_loader_factory.mojom.h"
- #include "services/network/test/test_network_connection_tracker.h"
- #include "url/scheme_host_port.h"
- #if BUILDFLAG(IS_MAC)
- #include "base/mac/scoped_nsautorelease_pool.h"
- #endif
- // This is a simple utility that initializes an mcs client and
- // prints out any events.
- namespace gcm {
- namespace {
- const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
- // Number of initial errors (in sequence) to ignore before applying
- // exponential back-off rules.
- 0,
- // Initial delay for exponential back-off in ms.
- 15000, // 15 seconds.
- // Factor by which the waiting time will be multiplied.
- 2,
- // Fuzzing percentage. ex: 10% will spread requests randomly
- // between 90%-100% of the calculated time.
- 0.5, // 50%.
- // Maximum amount of time we are willing to delay our request in ms.
- 1000 * 60 * 5, // 5 minutes.
- // Time to keep an entry from being discarded even when it
- // has no significant state, -1 to never discard.
- -1,
- // Don't use initial delay unless the last request was an error.
- false,
- };
- // Default values used to communicate with the check-in server.
- const char kChromeVersion[] = "Chrome MCS Probe";
- // The default server to communicate with.
- const char kMCSServerHost[] = "mtalk.google.com";
- const uint16_t kMCSServerPort = 5228;
- // Command line switches.
- const char kRMQFileName[] = "rmq_file";
- const char kAndroidIdSwitch[] = "android_id";
- const char kSecretSwitch[] = "secret";
- const char kLogFileSwitch[] = "log-file";
- const char kIgnoreCertSwitch[] = "ignore-certs";
- const char kServerHostSwitch[] = "host";
- const char kServerPortSwitch[] = "port";
- void MessageReceivedCallback(const MCSMessage& message) {
- LOG(INFO) << "Received message with id "
- << GetPersistentId(message.GetProtobuf()) << " and tag "
- << static_cast<int>(message.tag());
- if (message.tag() == kDataMessageStanzaTag) {
- const mcs_proto::DataMessageStanza& data_message =
- reinterpret_cast<const mcs_proto::DataMessageStanza&>(
- message.GetProtobuf());
- DVLOG(1) << " to: " << data_message.to();
- DVLOG(1) << " from: " << data_message.from();
- DVLOG(1) << " category: " << data_message.category();
- DVLOG(1) << " sent: " << data_message.sent();
- for (int i = 0; i < data_message.app_data_size(); ++i) {
- DVLOG(1) << " App data " << i << " "
- << data_message.app_data(i).key() << " : "
- << data_message.app_data(i).value();
- }
- }
- }
- void MessageSentCallback(int64_t user_serial_number,
- const std::string& app_id,
- const std::string& message_id,
- MCSClient::MessageSendStatus status) {
- LOG(INFO) << "Message sent. Serial number: " << user_serial_number
- << " Application ID: " << app_id
- << " Message ID: " << message_id
- << " Message send status: " << status;
- }
- // A cert verifier that access all certificates.
- class MyTestCertVerifier : public net::CertVerifier {
- public:
- MyTestCertVerifier() {}
- ~MyTestCertVerifier() override {}
- int Verify(const RequestParams& params,
- net::CertVerifyResult* verify_result,
- net::CompletionOnceCallback callback,
- std::unique_ptr<Request>* out_req,
- const net::NetLogWithSource& net_log) override {
- verify_result->Reset();
- verify_result->verified_cert = params.certificate();
- return net::OK;
- }
- void SetConfig(const Config& config) override {}
- };
- class MCSProbeAuthPreferences : public net::HttpAuthPreferences {
- public:
- MCSProbeAuthPreferences() {}
- ~MCSProbeAuthPreferences() override {}
- bool NegotiateDisableCnameLookup() const override { return false; }
- bool NegotiateEnablePort() const override { return false; }
- bool CanUseDefaultCredentials(
- const url::SchemeHostPort& auth_scheme_host_port) const override {
- return false;
- }
- net::HttpAuth::DelegationType GetDelegationType(
- const url::SchemeHostPort& auth_scheme_host_port) const override {
- return net::HttpAuth::DelegationType::kNone;
- }
- };
- class MCSProbe {
- public:
- explicit MCSProbe(const base::CommandLine& command_line);
- ~MCSProbe();
- void Start();
- uint64_t android_id() const { return android_id_; }
- uint64_t secret() const { return secret_; }
- private:
- void RequestProxyResolvingSocketFactory(
- mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
- receiver);
- void CheckIn();
- void InitializeNetworkState();
- void LoadCallback(std::unique_ptr<GCMStore::LoadResult> load_result);
- void UpdateCallback(bool success);
- void ErrorCallback();
- void OnCheckInCompleted(
- net::HttpStatusCode response_code,
- const checkin_proto::AndroidCheckinResponse& checkin_response);
- void StartMCSLogin();
- base::DefaultClock clock_;
- base::CommandLine command_line_;
- base::FilePath gcm_store_path_;
- uint64_t android_id_;
- uint64_t secret_;
- std::string server_host_;
- int server_port_;
- // Network state.
- std::unique_ptr<network::TestNetworkConnectionTracker>
- network_connection_tracker_;
- std::unique_ptr<net::URLRequestContext> url_request_context_;
- net::NetLog* net_log_;
- std::unique_ptr<net::FileNetLogObserver> logger_;
- MCSProbeAuthPreferences http_auth_preferences_;
- FakeGCMStatsRecorder recorder_;
- std::unique_ptr<GCMStore> gcm_store_;
- std::unique_ptr<MCSClient> mcs_client_;
- std::unique_ptr<CheckinRequest> checkin_request_;
- std::unique_ptr<ConnectionFactoryImpl> connection_factory_;
- base::Thread file_thread_;
- std::unique_ptr<network::NetworkContext> network_context_;
- mojo::Remote<network::mojom::NetworkContext> network_context_remote_;
- mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
- std::unique_ptr<base::RunLoop> run_loop_;
- };
- MCSProbe::MCSProbe(const base::CommandLine& command_line)
- : command_line_(command_line),
- gcm_store_path_(base::FilePath(FILE_PATH_LITERAL("gcm_store"))),
- android_id_(0),
- secret_(0),
- server_port_(0),
- network_connection_tracker_(
- network::TestNetworkConnectionTracker::CreateInstance()),
- net_log_(net::NetLog::Get()),
- file_thread_("FileThread") {
- network_connection_tracker_->SetConnectionType(
- network::mojom::ConnectionType::CONNECTION_ETHERNET);
- if (command_line.HasSwitch(kRMQFileName)) {
- gcm_store_path_ = command_line.GetSwitchValuePath(kRMQFileName);
- }
- if (command_line.HasSwitch(kAndroidIdSwitch)) {
- base::StringToUint64(command_line.GetSwitchValueASCII(kAndroidIdSwitch),
- &android_id_);
- }
- if (command_line.HasSwitch(kSecretSwitch)) {
- base::StringToUint64(command_line.GetSwitchValueASCII(kSecretSwitch),
- &secret_);
- }
- server_host_ = kMCSServerHost;
- if (command_line.HasSwitch(kServerHostSwitch)) {
- server_host_ = command_line.GetSwitchValueASCII(kServerHostSwitch);
- }
- server_port_ = kMCSServerPort;
- if (command_line.HasSwitch(kServerPortSwitch)) {
- base::StringToInt(command_line.GetSwitchValueASCII(kServerPortSwitch),
- &server_port_);
- }
- }
- MCSProbe::~MCSProbe() {
- if (logger_)
- logger_->StopObserving(nullptr, base::OnceClosure());
- file_thread_.Stop();
- }
- void MCSProbe::Start() {
- file_thread_.Start();
- InitializeNetworkState();
- std::vector<GURL> endpoints(
- 1, GURL("https://" +
- net::HostPortPair(server_host_, server_port_).ToString()));
- connection_factory_ = std::make_unique<ConnectionFactoryImpl>(
- endpoints, kDefaultBackoffPolicy,
- base::BindRepeating(&MCSProbe::RequestProxyResolvingSocketFactory,
- base::Unretained(this)),
- base::ThreadTaskRunnerHandle::Get(), &recorder_,
- network_connection_tracker_.get());
- gcm_store_ = std::make_unique<GCMStoreImpl>(
- gcm_store_path_, /*remove_account_mappings_with_email_key=*/true,
- file_thread_.task_runner(), std::make_unique<FakeEncryptor>());
- mcs_client_ = std::make_unique<MCSClient>(
- "probe", &clock_, connection_factory_.get(), gcm_store_.get(),
- base::ThreadTaskRunnerHandle::Get(), &recorder_);
- run_loop_ = std::make_unique<base::RunLoop>();
- gcm_store_->Load(
- GCMStore::CREATE_IF_MISSING,
- base::BindOnce(&MCSProbe::LoadCallback, base::Unretained(this)));
- run_loop_->Run();
- }
- void MCSProbe::LoadCallback(std::unique_ptr<GCMStore::LoadResult> load_result) {
- DCHECK(load_result->success);
- if (android_id_ != 0 && secret_ != 0) {
- DVLOG(1) << "Presetting MCS id " << android_id_;
- load_result->device_android_id = android_id_;
- load_result->device_security_token = secret_;
- gcm_store_->SetDeviceCredentials(
- android_id_, secret_,
- base::BindOnce(&MCSProbe::UpdateCallback, base::Unretained(this)));
- } else {
- android_id_ = load_result->device_android_id;
- secret_ = load_result->device_security_token;
- DVLOG(1) << "Loaded MCS id " << android_id_;
- }
- mcs_client_->Initialize(
- base::BindRepeating(&MCSProbe::ErrorCallback, base::Unretained(this)),
- base::BindRepeating(&MessageReceivedCallback),
- base::BindRepeating(&MessageSentCallback), std::move(load_result));
- if (!android_id_ || !secret_) {
- DVLOG(1) << "Checkin to generate new MCS credentials.";
- CheckIn();
- return;
- }
- StartMCSLogin();
- }
- void MCSProbe::UpdateCallback(bool success) {
- }
- void MCSProbe::InitializeNetworkState() {
- if (command_line_.HasSwitch(kLogFileSwitch)) {
- base::FilePath log_path = command_line_.GetSwitchValuePath(kLogFileSwitch);
- net::NetLogCaptureMode capture_mode =
- net::NetLogCaptureMode::kIncludeSensitive;
- logger_ = net::FileNetLogObserver::CreateUnbounded(log_path, capture_mode,
- nullptr);
- logger_->StartObserving(net_log_);
- }
- net::URLRequestContextBuilder builder;
- builder.set_net_log(net_log_);
- builder.set_host_resolver(
- net::HostResolver::CreateStandaloneResolver(net_log_));
- http_auth_preferences_.set_allowed_schemes(
- std::set<std::string>{net::kBasicAuthScheme});
- builder.SetHttpAuthHandlerFactory(
- net::HttpAuthHandlerRegistryFactory::Create(&http_auth_preferences_));
- builder.set_proxy_resolution_service(
- net::ConfiguredProxyResolutionService::CreateDirect());
- if (command_line_.HasSwitch(kIgnoreCertSwitch))
- builder.SetCertVerifier(std::make_unique<MyTestCertVerifier>());
- url_request_context_ = builder.Build();
- // Wrap it up with network service APIs.
- network_context_ = std::make_unique<network::NetworkContext>(
- nullptr /* network_service */,
- network_context_remote_.BindNewPipeAndPassReceiver(),
- url_request_context_.get(),
- /*cors_exempt_header_list=*/std::vector<std::string>());
- auto url_loader_factory_params =
- network::mojom::URLLoaderFactoryParams::New();
- url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
- url_loader_factory_params->is_corb_enabled = false;
- network_context_->CreateURLLoaderFactory(
- url_loader_factory_.BindNewPipeAndPassReceiver(),
- std::move(url_loader_factory_params));
- shared_url_loader_factory_ =
- base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
- url_loader_factory_.get());
- }
- void MCSProbe::ErrorCallback() {
- LOG(INFO) << "MCS error happened";
- }
- void MCSProbe::RequestProxyResolvingSocketFactory(
- mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
- receiver) {
- return network_context_->CreateProxyResolvingSocketFactory(
- std::move(receiver));
- }
- void MCSProbe::CheckIn() {
- LOG(INFO) << "Check-in request initiated.";
- checkin_proto::ChromeBuildProto chrome_build_proto;
- chrome_build_proto.set_platform(
- checkin_proto::ChromeBuildProto::PLATFORM_LINUX);
- chrome_build_proto.set_channel(
- checkin_proto::ChromeBuildProto::CHANNEL_CANARY);
- chrome_build_proto.set_chrome_version(kChromeVersion);
- CheckinRequest::RequestInfo request_info(0, 0,
- std::map<std::string, std::string>(),
- std::string(), chrome_build_proto);
- checkin_request_ = std::make_unique<CheckinRequest>(
- GServicesSettings().GetCheckinURL(), request_info, kDefaultBackoffPolicy,
- base::BindOnce(&MCSProbe::OnCheckInCompleted, base::Unretained(this)),
- shared_url_loader_factory_, base::ThreadTaskRunnerHandle::Get(),
- &recorder_);
- checkin_request_->Start();
- }
- void MCSProbe::OnCheckInCompleted(
- net::HttpStatusCode response_code,
- const checkin_proto::AndroidCheckinResponse& checkin_response) {
- bool success = response_code == net::HTTP_OK &&
- checkin_response.has_android_id() &&
- checkin_response.android_id() != 0UL &&
- checkin_response.has_security_token() &&
- checkin_response.security_token() != 0UL;
- LOG(INFO) << "Check-in request completion "
- << (success ? "success!" : "failure!");
- if (!success)
- return;
- android_id_ = checkin_response.android_id();
- secret_ = checkin_response.security_token();
- gcm_store_->SetDeviceCredentials(
- android_id_, secret_,
- base::BindOnce(&MCSProbe::UpdateCallback, base::Unretained(this)));
- StartMCSLogin();
- }
- void MCSProbe::StartMCSLogin() {
- LOG(INFO) << "MCS login initiated.";
- mcs_client_->Login(android_id_, secret_);
- }
- int MCSProbeMain(int argc, char* argv[]) {
- base::AtExitManager exit_manager;
- base::CommandLine::Init(argc, argv);
- logging::LoggingSettings settings;
- settings.logging_dest =
- logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
- logging::InitLogging(settings);
- mojo::core::Init();
- base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
- base::ThreadPoolInstance::CreateAndStartWithDefaultParams("MCSProbe");
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
- MCSProbe mcs_probe(command_line);
- mcs_probe.Start();
- base::RunLoop run_loop;
- run_loop.Run();
- base::ThreadPoolInstance::Get()->Shutdown();
- return 0;
- }
- } // namespace
- } // namespace gcm
- int main(int argc, char* argv[]) {
- return gcm::MCSProbeMain(argc, argv);
- }
|