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 "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"
35 #if defined(OS_MACOSX)
36 #include "base/mac/scoped_nsautorelease_pool.h"
39 // This is a simple utility that initializes a sync notifier and
40 // listens to any received notifications.
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";
51 // Class to print received notifications events.
52 class NotificationPrinter
: public InvalidationHandler
{
54 NotificationPrinter() {}
55 virtual ~NotificationPrinter() {}
57 virtual void OnInvalidatorStateChange(InvalidatorState state
) OVERRIDE
{
58 LOG(INFO
) << "Invalidator state changed to "
59 << InvalidatorStateToString(state
);
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();
71 virtual std::string
GetOwnerName() const OVERRIDE
{
72 return "NotificationPrinter";
76 DISALLOW_COPY_AND_ASSIGN(NotificationPrinter
);
79 // Needed to use a real host resolver.
80 class MyTestURLRequestContext
: public net::TestURLRequestContext
{
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());
90 virtual ~MyTestURLRequestContext() {}
93 class MyTestURLRequestContextGetter
: public net::TestURLRequestContextGetter
{
95 explicit MyTestURLRequestContextGetter(
96 const scoped_refptr
<base::SingleThreadTaskRunner
>& io_task_runner
)
97 : TestURLRequestContextGetter(io_task_runner
) {}
99 virtual net::TestURLRequestContext
* GetURLRequestContext() OVERRIDE
{
100 // Construct |context_| lazily so it gets constructed on the right
101 // thread (the IO thread).
103 context_
.reset(new MyTestURLRequestContext());
104 return context_
.get();
108 virtual ~MyTestURLRequestContextGetter() {}
110 scoped_ptr
<MyTestURLRequestContext
> context_
;
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
;
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.";
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.";
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.";
138 return notifier_options
;
141 int SyncListenNotificationsMain(int argc
, char* argv
[]) {
142 using namespace syncer
;
143 #if defined(OS_MACOSX)
144 base::mac::ScopedNSAutoreleasePool pool
;
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
);
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
);
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@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",
172 kEmailSwitch
, kTokenSwitch
, kHostPortSwitch
,
173 kTrySslTcpFirstSwitch
, kAllowInsecureConnectionSwitch
);
177 // Set up objects that monitor the network.
178 scoped_ptr
<net::NetworkChangeNotifier
> network_change_notifier(
179 net::NetworkChangeNotifier::Create());
181 const notifier::NotifierOptions
& notifier_options
=
182 ParseNotifierOptions(
184 new MyTestURLRequestContextGetter(io_thread
.message_loop_proxy()));
185 syncer::NetworkChannelCreator network_channel_creator
=
186 syncer::NonBlockingInvalidator::MakePushClientChannelCreator(
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
,
198 notifier_options
.request_context_getter
));
200 NotificationPrinter notification_printer
;
202 invalidator
->UpdateCredentials(email
, token
);
204 // Listen for notifications for all known types.
205 invalidator
->RegisterHandler(¬ification_printer
);
206 invalidator
->UpdateRegisteredIds(
207 ¬ification_printer
, ModelTypeSetToObjectIdSet(ModelTypeSet::All()));
211 invalidator
->UnregisterHandler(¬ification_printer
);
217 } // namespace syncer
219 int main(int argc
, char* argv
[]) {
220 return syncer::SyncListenNotificationsMain(argc
, argv
);