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