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