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