Home | History | Annotate | Download | only in tools
      1 // Copyright (c) 2012 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 #include <cstddef>
      6 #include <cstdio>
      7 #include <string>
      8 
      9 #include "base/at_exit.h"
     10 #include "base/command_line.h"
     11 #include "base/compiler_specific.h"
     12 #include "base/logging.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/rand_util.h"
     17 #include "base/threading/thread.h"
     18 #include "components/invalidation/non_blocking_invalidator.h"
     19 #include "jingle/notifier/base/notification_method.h"
     20 #include "jingle/notifier/base/notifier_options.h"
     21 #include "net/base/host_port_pair.h"
     22 #include "net/base/network_change_notifier.h"
     23 #include "net/dns/host_resolver.h"
     24 #include "net/http/transport_security_state.h"
     25 #include "net/url_request/url_request_test_util.h"
     26 #include "sync/internal_api/public/base/model_type.h"
     27 #include "sync/notifier/invalidation_handler.h"
     28 #include "sync/notifier/invalidation_state_tracker.h"
     29 #include "sync/notifier/invalidation_util.h"
     30 #include "sync/notifier/invalidator.h"
     31 #include "sync/notifier/object_id_invalidation_map.h"
     32 #include "sync/tools/null_invalidation_state_tracker.h"
     33 
     34 #if defined(OS_MACOSX)
     35 #include "base/mac/scoped_nsautorelease_pool.h"
     36 #endif
     37 
     38 // This is a simple utility that initializes a sync notifier and
     39 // listens to any received notifications.
     40 
     41 namespace syncer {
     42 namespace {
     43 
     44 const char kEmailSwitch[] = "email";
     45 const char kTokenSwitch[] = "token";
     46 const char kHostPortSwitch[] = "host-port";
     47 const char kTrySslTcpFirstSwitch[] = "try-ssltcp-first";
     48 const char kAllowInsecureConnectionSwitch[] = "allow-insecure-connection";
     49 
     50 // Class to print received notifications events.
     51 class NotificationPrinter : public InvalidationHandler {
     52  public:
     53   NotificationPrinter() {}
     54   virtual ~NotificationPrinter() {}
     55 
     56   virtual void OnInvalidatorStateChange(InvalidatorState state) OVERRIDE {
     57     LOG(INFO) << "Invalidator state changed to "
     58               << InvalidatorStateToString(state);
     59   }
     60 
     61   virtual void OnIncomingInvalidation(
     62       const ObjectIdInvalidationMap& invalidation_map) OVERRIDE {
     63     ObjectIdSet ids = invalidation_map.GetObjectIds();
     64     for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
     65       LOG(INFO) << "Remote invalidation: "
     66                 << invalidation_map.ToString();
     67     }
     68   }
     69 
     70   virtual std::string GetOwnerName() const OVERRIDE {
     71     return "NotificationPrinter";
     72   }
     73 
     74  private:
     75   DISALLOW_COPY_AND_ASSIGN(NotificationPrinter);
     76 };
     77 
     78 // Needed to use a real host resolver.
     79 class MyTestURLRequestContext : public net::TestURLRequestContext {
     80  public:
     81   MyTestURLRequestContext() : TestURLRequestContext(true) {
     82     context_storage_.set_host_resolver(
     83         net::HostResolver::CreateDefaultResolver(NULL));
     84     context_storage_.set_transport_security_state(
     85         new net::TransportSecurityState());
     86     Init();
     87   }
     88 
     89   virtual ~MyTestURLRequestContext() {}
     90 };
     91 
     92 class MyTestURLRequestContextGetter : public net::TestURLRequestContextGetter {
     93  public:
     94   explicit MyTestURLRequestContextGetter(
     95       const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy)
     96       : TestURLRequestContextGetter(io_message_loop_proxy) {}
     97 
     98   virtual net::TestURLRequestContext* GetURLRequestContext() OVERRIDE {
     99     // Construct |context_| lazily so it gets constructed on the right
    100     // thread (the IO thread).
    101     if (!context_)
    102       context_.reset(new MyTestURLRequestContext());
    103     return context_.get();
    104   }
    105 
    106  private:
    107   virtual ~MyTestURLRequestContextGetter() {}
    108 
    109   scoped_ptr<MyTestURLRequestContext> context_;
    110 };
    111 
    112 notifier::NotifierOptions ParseNotifierOptions(
    113     const CommandLine& command_line,
    114     const scoped_refptr<net::URLRequestContextGetter>&
    115         request_context_getter) {
    116   notifier::NotifierOptions notifier_options;
    117   notifier_options.request_context_getter = request_context_getter;
    118 
    119   if (command_line.HasSwitch(kHostPortSwitch)) {
    120     notifier_options.xmpp_host_port =
    121         net::HostPortPair::FromString(
    122             command_line.GetSwitchValueASCII(kHostPortSwitch));
    123     LOG(INFO) << "Using " << notifier_options.xmpp_host_port.ToString()
    124               << " for test sync notification server.";
    125   }
    126 
    127   notifier_options.try_ssltcp_first =
    128       command_line.HasSwitch(kTrySslTcpFirstSwitch);
    129   LOG_IF(INFO, notifier_options.try_ssltcp_first)
    130       << "Trying SSL/TCP port before XMPP port for notifications.";
    131 
    132   notifier_options.allow_insecure_connection =
    133       command_line.HasSwitch(kAllowInsecureConnectionSwitch);
    134   LOG_IF(INFO, notifier_options.allow_insecure_connection)
    135       << "Allowing insecure XMPP connections.";
    136 
    137   return notifier_options;
    138 }
    139 
    140 int SyncListenNotificationsMain(int argc, char* argv[]) {
    141   using namespace syncer;
    142 #if defined(OS_MACOSX)
    143   base::mac::ScopedNSAutoreleasePool pool;
    144 #endif
    145   base::AtExitManager exit_manager;
    146   CommandLine::Init(argc, argv);
    147   logging::LoggingSettings settings;
    148   settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
    149   logging::InitLogging(settings);
    150 
    151   base::MessageLoop ui_loop;
    152   base::Thread io_thread("IO thread");
    153   base::Thread::Options options;
    154   options.message_loop_type = base::MessageLoop::TYPE_IO;
    155   io_thread.StartWithOptions(options);
    156 
    157   // Parse command line.
    158   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    159   std::string email = command_line.GetSwitchValueASCII(kEmailSwitch);
    160   std::string token = command_line.GetSwitchValueASCII(kTokenSwitch);
    161   // TODO(akalin): Write a wrapper script that gets a token for an
    162   // email and password and passes that in to this utility.
    163   if (email.empty() || token.empty()) {
    164     std::printf("Usage: %s --%s=foo (at) bar.com --%s=token\n"
    165                 "[--%s=host:port] [--%s] [--%s]\n"
    166                 "Run chrome and set a breakpoint on\n"
    167                 "syncer::SyncManagerImpl::UpdateCredentials() "
    168                 "after logging into\n"
    169                 "sync to get the token to pass into this utility.\n",
    170                 argv[0],
    171                 kEmailSwitch, kTokenSwitch, kHostPortSwitch,
    172                 kTrySslTcpFirstSwitch, kAllowInsecureConnectionSwitch);
    173     return -1;
    174   }
    175 
    176   // Set up objects that monitor the network.
    177   scoped_ptr<net::NetworkChangeNotifier> network_change_notifier(
    178       net::NetworkChangeNotifier::Create());
    179 
    180   const notifier::NotifierOptions& notifier_options =
    181       ParseNotifierOptions(
    182           command_line,
    183           new MyTestURLRequestContextGetter(io_thread.message_loop_proxy()));
    184   syncer::NetworkChannelCreator network_channel_creator =
    185       syncer::NonBlockingInvalidator::MakePushClientChannelCreator(
    186           notifier_options);
    187   const char kClientInfo[] = "sync_listen_notifications";
    188   NullInvalidationStateTracker null_invalidation_state_tracker;
    189   scoped_ptr<Invalidator> invalidator(
    190       new NonBlockingInvalidator(
    191           network_channel_creator,
    192           base::RandBytesAsString(8),
    193           null_invalidation_state_tracker.GetSavedInvalidations(),
    194           null_invalidation_state_tracker.GetBootstrapData(),
    195           &null_invalidation_state_tracker,
    196           kClientInfo,
    197           notifier_options.request_context_getter));
    198 
    199   NotificationPrinter notification_printer;
    200 
    201   invalidator->UpdateCredentials(email, token);
    202 
    203   // Listen for notifications for all known types.
    204   invalidator->RegisterHandler(&notification_printer);
    205   invalidator->UpdateRegisteredIds(
    206       &notification_printer, ModelTypeSetToObjectIdSet(ModelTypeSet::All()));
    207 
    208   ui_loop.Run();
    209 
    210   invalidator->UnregisterHandler(&notification_printer);
    211   io_thread.Stop();
    212   return 0;
    213 }
    214 
    215 }  // namespace
    216 }  // namespace syncer
    217 
    218 int main(int argc, char* argv[]) {
    219   return syncer::SyncListenNotificationsMain(argc, argv);
    220 }
    221