[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / google_apis / gcm / tools / mcs_probe.cc
blob3f93fd083013985093a5cf29ef4f9a12375e51dc
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.
8 #include <cstddef>
9 #include <cstdio>
10 #include <string>
11 #include <vector>
13 #include "base/at_exit.h"
14 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/logging.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/message_loop/message_loop.h"
20 #include "base/run_loop.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/threading/thread.h"
23 #include "base/threading/worker_pool.h"
24 #include "base/time/default_clock.h"
25 #include "base/values.h"
26 #include "google_apis/gcm/base/fake_encryptor.h"
27 #include "google_apis/gcm/base/mcs_message.h"
28 #include "google_apis/gcm/base/mcs_util.h"
29 #include "google_apis/gcm/engine/checkin_request.h"
30 #include "google_apis/gcm/engine/connection_factory_impl.h"
31 #include "google_apis/gcm/engine/gcm_store_impl.h"
32 #include "google_apis/gcm/engine/gservices_settings.h"
33 #include "google_apis/gcm/engine/mcs_client.h"
34 #include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
35 #include "net/base/host_mapping_rules.h"
36 #include "net/base/net_log_logger.h"
37 #include "net/cert/cert_verifier.h"
38 #include "net/dns/host_resolver.h"
39 #include "net/http/http_auth_handler_factory.h"
40 #include "net/http/http_network_session.h"
41 #include "net/http/http_server_properties_impl.h"
42 #include "net/http/transport_security_state.h"
43 #include "net/socket/client_socket_factory.h"
44 #include "net/socket/ssl_client_socket.h"
45 #include "net/ssl/default_server_bound_cert_store.h"
46 #include "net/ssl/server_bound_cert_service.h"
47 #include "net/url_request/url_request_test_util.h"
49 #if defined(OS_MACOSX)
50 #include "base/mac/scoped_nsautorelease_pool.h"
51 #endif
53 // This is a simple utility that initializes an mcs client and
54 // prints out any events.
55 namespace gcm {
56 namespace {
58 const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
59 // Number of initial errors (in sequence) to ignore before applying
60 // exponential back-off rules.
63 // Initial delay for exponential back-off in ms.
64 15000, // 15 seconds.
66 // Factor by which the waiting time will be multiplied.
69 // Fuzzing percentage. ex: 10% will spread requests randomly
70 // between 90%-100% of the calculated time.
71 0.5, // 50%.
73 // Maximum amount of time we are willing to delay our request in ms.
74 1000 * 60 * 5, // 5 minutes.
76 // Time to keep an entry from being discarded even when it
77 // has no significant state, -1 to never discard.
78 -1,
80 // Don't use initial delay unless the last request was an error.
81 false,
84 // Default values used to communicate with the check-in server.
85 const char kChromeVersion[] = "Chrome MCS Probe";
87 // The default server to communicate with.
88 const char kMCSServerHost[] = "mtalk.google.com";
89 const uint16 kMCSServerPort = 5228;
91 // Command line switches.
92 const char kRMQFileName[] = "rmq_file";
93 const char kAndroidIdSwitch[] = "android_id";
94 const char kSecretSwitch[] = "secret";
95 const char kLogFileSwitch[] = "log-file";
96 const char kIgnoreCertSwitch[] = "ignore-certs";
97 const char kServerHostSwitch[] = "host";
98 const char kServerPortSwitch[] = "port";
100 void MessageReceivedCallback(const MCSMessage& message) {
101 LOG(INFO) << "Received message with id "
102 << GetPersistentId(message.GetProtobuf()) << " and tag "
103 << static_cast<int>(message.tag());
105 if (message.tag() == kDataMessageStanzaTag) {
106 const mcs_proto::DataMessageStanza& data_message =
107 reinterpret_cast<const mcs_proto::DataMessageStanza&>(
108 message.GetProtobuf());
109 DVLOG(1) << " to: " << data_message.to();
110 DVLOG(1) << " from: " << data_message.from();
111 DVLOG(1) << " category: " << data_message.category();
112 DVLOG(1) << " sent: " << data_message.sent();
113 for (int i = 0; i < data_message.app_data_size(); ++i) {
114 DVLOG(1) << " App data " << i << " "
115 << data_message.app_data(i).key() << " : "
116 << data_message.app_data(i).value();
121 void MessageSentCallback(int64 user_serial_number,
122 const std::string& app_id,
123 const std::string& message_id,
124 MCSClient::MessageSendStatus status) {
125 LOG(INFO) << "Message sent. Serial number: " << user_serial_number
126 << " Application ID: " << app_id
127 << " Message ID: " << message_id
128 << " Message send status: " << status;
131 // Needed to use a real host resolver.
132 class MyTestURLRequestContext : public net::TestURLRequestContext {
133 public:
134 MyTestURLRequestContext() : TestURLRequestContext(true) {
135 context_storage_.set_host_resolver(
136 net::HostResolver::CreateDefaultResolver(NULL));
137 context_storage_.set_transport_security_state(
138 new net::TransportSecurityState());
139 Init();
142 virtual ~MyTestURLRequestContext() {}
145 class MyTestURLRequestContextGetter : public net::TestURLRequestContextGetter {
146 public:
147 explicit MyTestURLRequestContextGetter(
148 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy)
149 : TestURLRequestContextGetter(io_message_loop_proxy) {}
151 virtual net::TestURLRequestContext* GetURLRequestContext() OVERRIDE {
152 // Construct |context_| lazily so it gets constructed on the right
153 // thread (the IO thread).
154 if (!context_)
155 context_.reset(new MyTestURLRequestContext());
156 return context_.get();
159 private:
160 virtual ~MyTestURLRequestContextGetter() {}
162 scoped_ptr<MyTestURLRequestContext> context_;
165 // A net log that logs all events by default.
166 class MyTestNetLog : public net::NetLog {
167 public:
168 MyTestNetLog() {
169 SetBaseLogLevel(LOG_ALL);
171 virtual ~MyTestNetLog() {}
174 // A cert verifier that access all certificates.
175 class MyTestCertVerifier : public net::CertVerifier {
176 public:
177 MyTestCertVerifier() {}
178 virtual ~MyTestCertVerifier() {}
180 virtual int Verify(net::X509Certificate* cert,
181 const std::string& hostname,
182 int flags,
183 net::CRLSet* crl_set,
184 net::CertVerifyResult* verify_result,
185 const net::CompletionCallback& callback,
186 RequestHandle* out_req,
187 const net::BoundNetLog& net_log) OVERRIDE {
188 return net::OK;
191 virtual void CancelRequest(RequestHandle req) OVERRIDE {
192 // Do nothing.
196 class MCSProbe {
197 public:
198 MCSProbe(
199 const CommandLine& command_line,
200 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter);
201 ~MCSProbe();
203 void Start();
205 uint64 android_id() const { return android_id_; }
206 uint64 secret() const { return secret_; }
208 private:
209 void CheckIn();
210 void InitializeNetworkState();
211 void BuildNetworkSession();
213 void LoadCallback(scoped_ptr<GCMStore::LoadResult> load_result);
214 void UpdateCallback(bool success);
215 void ErrorCallback();
216 void OnCheckInCompleted(
217 const checkin_proto::AndroidCheckinResponse& checkin_response);
218 void StartMCSLogin();
220 base::DefaultClock clock_;
222 CommandLine command_line_;
224 base::FilePath gcm_store_path_;
225 uint64 android_id_;
226 uint64 secret_;
227 std::string server_host_;
228 int server_port_;
230 // Network state.
231 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
232 MyTestNetLog net_log_;
233 scoped_ptr<net::NetLogLogger> logger_;
234 scoped_ptr<base::Value> net_constants_;
235 scoped_ptr<net::HostResolver> host_resolver_;
236 scoped_ptr<net::CertVerifier> cert_verifier_;
237 scoped_ptr<net::ServerBoundCertService> system_server_bound_cert_service_;
238 scoped_ptr<net::TransportSecurityState> transport_security_state_;
239 scoped_ptr<net::URLSecurityManager> url_security_manager_;
240 scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory_;
241 scoped_ptr<net::HttpServerPropertiesImpl> http_server_properties_;
242 scoped_ptr<net::HostMappingRules> host_mapping_rules_;
243 scoped_refptr<net::HttpNetworkSession> network_session_;
244 scoped_ptr<net::ProxyService> proxy_service_;
246 GCMStatsRecorder recorder_;
247 scoped_ptr<GCMStore> gcm_store_;
248 scoped_ptr<MCSClient> mcs_client_;
249 scoped_ptr<CheckinRequest> checkin_request_;
251 scoped_ptr<ConnectionFactoryImpl> connection_factory_;
253 base::Thread file_thread_;
255 scoped_ptr<base::RunLoop> run_loop_;
258 MCSProbe::MCSProbe(
259 const CommandLine& command_line,
260 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter)
261 : command_line_(command_line),
262 gcm_store_path_(base::FilePath(FILE_PATH_LITERAL("gcm_store"))),
263 android_id_(0),
264 secret_(0),
265 server_port_(0),
266 url_request_context_getter_(url_request_context_getter),
267 file_thread_("FileThread") {
268 if (command_line.HasSwitch(kRMQFileName)) {
269 gcm_store_path_ = command_line.GetSwitchValuePath(kRMQFileName);
271 if (command_line.HasSwitch(kAndroidIdSwitch)) {
272 base::StringToUint64(command_line.GetSwitchValueASCII(kAndroidIdSwitch),
273 &android_id_);
275 if (command_line.HasSwitch(kSecretSwitch)) {
276 base::StringToUint64(command_line.GetSwitchValueASCII(kSecretSwitch),
277 &secret_);
279 server_host_ = kMCSServerHost;
280 if (command_line.HasSwitch(kServerHostSwitch)) {
281 server_host_ = command_line.GetSwitchValueASCII(kServerHostSwitch);
283 server_port_ = kMCSServerPort;
284 if (command_line.HasSwitch(kServerPortSwitch)) {
285 base::StringToInt(command_line.GetSwitchValueASCII(kServerPortSwitch),
286 &server_port_);
290 MCSProbe::~MCSProbe() {
291 file_thread_.Stop();
294 void MCSProbe::Start() {
295 file_thread_.Start();
296 InitializeNetworkState();
297 BuildNetworkSession();
298 std::vector<GURL> endpoints(1,
299 GURL("https://" +
300 net::HostPortPair(server_host_,
301 server_port_).ToString()));
302 connection_factory_.reset(
303 new ConnectionFactoryImpl(endpoints,
304 kDefaultBackoffPolicy,
305 network_session_,
306 &net_log_,
307 &recorder_));
308 gcm_store_.reset(
309 new GCMStoreImpl(gcm_store_path_,
310 file_thread_.message_loop_proxy(),
311 make_scoped_ptr<Encryptor>(new FakeEncryptor)));
312 mcs_client_.reset(new MCSClient("probe",
313 &clock_,
314 connection_factory_.get(),
315 gcm_store_.get(),
316 &recorder_));
317 run_loop_.reset(new base::RunLoop());
318 gcm_store_->Load(base::Bind(&MCSProbe::LoadCallback,
319 base::Unretained(this)));
320 run_loop_->Run();
323 void MCSProbe::LoadCallback(scoped_ptr<GCMStore::LoadResult> load_result) {
324 DCHECK(load_result->success);
325 if (android_id_ != 0 && secret_ != 0) {
326 DVLOG(1) << "Presetting MCS id " << android_id_;
327 load_result->device_android_id = android_id_;
328 load_result->device_security_token = secret_;
329 gcm_store_->SetDeviceCredentials(android_id_,
330 secret_,
331 base::Bind(&MCSProbe::UpdateCallback,
332 base::Unretained(this)));
333 } else {
334 android_id_ = load_result->device_android_id;
335 secret_ = load_result->device_security_token;
336 DVLOG(1) << "Loaded MCS id " << android_id_;
338 mcs_client_->Initialize(
339 base::Bind(&MCSProbe::ErrorCallback, base::Unretained(this)),
340 base::Bind(&MessageReceivedCallback),
341 base::Bind(&MessageSentCallback),
342 load_result.Pass());
344 if (!android_id_ || !secret_) {
345 DVLOG(1) << "Checkin to generate new MCS credentials.";
346 CheckIn();
347 return;
350 StartMCSLogin();
353 void MCSProbe::UpdateCallback(bool success) {
356 void MCSProbe::InitializeNetworkState() {
357 FILE* log_file = NULL;
358 if (command_line_.HasSwitch(kLogFileSwitch)) {
359 base::FilePath log_path = command_line_.GetSwitchValuePath(kLogFileSwitch);
360 #if defined(OS_WIN)
361 log_file = _wfopen(log_path.value().c_str(), L"w");
362 #elif defined(OS_POSIX)
363 log_file = fopen(log_path.value().c_str(), "w");
364 #endif
366 net_constants_.reset(net::NetLogLogger::GetConstants());
367 if (log_file != NULL) {
368 logger_.reset(new net::NetLogLogger(log_file, *net_constants_));
369 logger_->StartObserving(&net_log_);
372 host_resolver_ = net::HostResolver::CreateDefaultResolver(&net_log_);
374 if (command_line_.HasSwitch(kIgnoreCertSwitch)) {
375 cert_verifier_.reset(new MyTestCertVerifier());
376 } else {
377 cert_verifier_.reset(net::CertVerifier::CreateDefault());
379 system_server_bound_cert_service_.reset(
380 new net::ServerBoundCertService(
381 new net::DefaultServerBoundCertStore(NULL),
382 base::WorkerPool::GetTaskRunner(true)));
384 transport_security_state_.reset(new net::TransportSecurityState());
385 url_security_manager_.reset(net::URLSecurityManager::Create(NULL, NULL));
386 http_auth_handler_factory_.reset(
387 net::HttpAuthHandlerRegistryFactory::Create(
388 std::vector<std::string>(1, "basic"),
389 url_security_manager_.get(),
390 host_resolver_.get(),
391 std::string(),
392 false,
393 false));
394 http_server_properties_.reset(new net::HttpServerPropertiesImpl());
395 host_mapping_rules_.reset(new net::HostMappingRules());
396 proxy_service_.reset(net::ProxyService::CreateDirectWithNetLog(&net_log_));
399 void MCSProbe::BuildNetworkSession() {
400 net::HttpNetworkSession::Params session_params;
401 session_params.host_resolver = host_resolver_.get();
402 session_params.cert_verifier = cert_verifier_.get();
403 session_params.server_bound_cert_service =
404 system_server_bound_cert_service_.get();
405 session_params.transport_security_state = transport_security_state_.get();
406 session_params.ssl_config_service = new net::SSLConfigServiceDefaults();
407 session_params.http_auth_handler_factory = http_auth_handler_factory_.get();
408 session_params.http_server_properties =
409 http_server_properties_->GetWeakPtr();
410 session_params.network_delegate = NULL; // TODO(zea): implement?
411 session_params.host_mapping_rules = host_mapping_rules_.get();
412 session_params.ignore_certificate_errors = true;
413 session_params.http_pipelining_enabled = false;
414 session_params.testing_fixed_http_port = 0;
415 session_params.testing_fixed_https_port = 0;
416 session_params.net_log = &net_log_;
417 session_params.proxy_service = proxy_service_.get();
419 network_session_ = new net::HttpNetworkSession(session_params);
422 void MCSProbe::ErrorCallback() {
423 LOG(INFO) << "MCS error happened";
426 void MCSProbe::CheckIn() {
427 LOG(INFO) << "Check-in request initiated.";
428 checkin_proto::ChromeBuildProto chrome_build_proto;
429 chrome_build_proto.set_platform(
430 checkin_proto::ChromeBuildProto::PLATFORM_LINUX);
431 chrome_build_proto.set_channel(
432 checkin_proto::ChromeBuildProto::CHANNEL_CANARY);
433 chrome_build_proto.set_chrome_version(kChromeVersion);
435 CheckinRequest::RequestInfo request_info(
436 0, 0, std::string(), std::vector<std::string>(), chrome_build_proto);
438 checkin_request_.reset(new CheckinRequest(
439 GServicesSettings::DefaultCheckinURL(),
440 request_info,
441 kDefaultBackoffPolicy,
442 base::Bind(&MCSProbe::OnCheckInCompleted, base::Unretained(this)),
443 url_request_context_getter_.get(),
444 &recorder_));
445 checkin_request_->Start();
448 void MCSProbe::OnCheckInCompleted(
449 const checkin_proto::AndroidCheckinResponse& checkin_response) {
450 bool success = checkin_response.has_android_id() &&
451 checkin_response.android_id() != 0UL &&
452 checkin_response.has_security_token() &&
453 checkin_response.security_token() != 0UL;
454 LOG(INFO) << "Check-in request completion "
455 << (success ? "success!" : "failure!");
457 if (!success)
458 return;
460 android_id_ = checkin_response.android_id();
461 secret_ = checkin_response.security_token();
463 gcm_store_->SetDeviceCredentials(android_id_,
464 secret_,
465 base::Bind(&MCSProbe::UpdateCallback,
466 base::Unretained(this)));
468 StartMCSLogin();
471 void MCSProbe::StartMCSLogin() {
472 LOG(INFO) << "MCS login initiated.";
474 mcs_client_->Login(android_id_, secret_);
477 int MCSProbeMain(int argc, char* argv[]) {
478 base::AtExitManager exit_manager;
480 CommandLine::Init(argc, argv);
481 logging::LoggingSettings settings;
482 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
483 logging::InitLogging(settings);
485 base::MessageLoopForIO message_loop;
487 // For check-in and creating registration ids.
488 const scoped_refptr<MyTestURLRequestContextGetter> context_getter =
489 new MyTestURLRequestContextGetter(
490 base::MessageLoop::current()->message_loop_proxy());
492 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
494 MCSProbe mcs_probe(command_line, context_getter);
495 mcs_probe.Start();
497 base::RunLoop run_loop;
498 run_loop.Run();
500 return 0;
503 } // namespace
504 } // namespace gcm
506 int main(int argc, char* argv[]) {
507 return gcm::MCSProbeMain(argc, argv);