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