blob: 887ba94d177ec6089594066db30769067cc487b0 [file] [log] [blame]
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001// Copyright (c) 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#include "chrome/browser/devtools/tethering_adb_filter.h"
6
7#include <map>
8
9#include "base/bind.h"
10#include "base/compiler_specific.h"
Ben Murdoch2385ea32013-08-06 11:01:04 +010011#include "base/message_loop/message_loop.h"
12#include "base/prefs/pref_service.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010013#include "base/strings/string_number_conversions.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010014#include "base/strings/string_util.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010015#include "base/strings/stringprintf.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010016#include "chrome/browser/devtools/adb_client_socket.h"
Ben Murdoch2385ea32013-08-06 11:01:04 +010017#include "chrome/browser/devtools/adb_web_socket.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010018#include "chrome/browser/devtools/devtools_protocol.h"
Ben Murdoch2385ea32013-08-06 11:01:04 +010019#include "chrome/common/pref_names.h"
20#include "content/public/browser/browser_thread.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010021#include "net/base/address_list.h"
22#include "net/base/net_errors.h"
23#include "net/base/net_util.h"
24#include "net/dns/host_resolver.h"
25#include "net/socket/tcp_client_socket.h"
26
Ben Murdoch2385ea32013-08-06 11:01:04 +010027using content::BrowserThread;
28
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010029namespace {
30
Ben Murdoch2385ea32013-08-06 11:01:04 +010031const int kAdbPort = 5037;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010032const int kBufferSize = 16 * 1024;
33
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010034static const char kPortAttribute[] = "port";
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010035static const char kConnectionIdAttribute[] = "connectionId";
36static const char kTetheringAccepted[] = "Tethering.accepted";
37static const char kTetheringBind[] = "Tethering.bind";
38static const char kTetheringUnbind[] = "Tethering.unbind";
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010039static const char kLocalAbstractCommand[] = "localabstract:%s";
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010040
Ben Murdoch2385ea32013-08-06 11:01:04 +010041static const char kDevToolsRemoteSocketName[] = "chrome_devtools_remote";
42static const char kDevToolsRemoteBrowserTarget[] = "/devtools/browser";
43
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010044class SocketTunnel {
45 public:
46 explicit SocketTunnel(const std::string& location)
47 : location_(location),
48 pending_writes_(0),
49 pending_destruction_(false) {
50 }
51
52 void Start(int result, net::StreamSocket* socket) {
53 if (result < 0) {
54 SelfDestruct();
55 return;
56 }
57 remote_socket_.reset(socket);
58
59 std::vector<std::string> tokens;
60 Tokenize(location_, ":", &tokens);
61 int port = 0;
62 if (tokens.size() != 2 || !base::StringToInt(tokens[1], &port)) {
63 SelfDestruct();
64 return;
65 }
66
67 host_resolver_ = net::HostResolver::CreateDefaultResolver(NULL);
68 net::HostResolver::RequestInfo request_info(
69 net::HostPortPair(tokens[0], port));
70 result = host_resolver_->Resolve(
71 request_info, &address_list_,
72 base::Bind(&SocketTunnel::OnResolved, base::Unretained(this)),
73 NULL, net::BoundNetLog());
74 if (result != net::ERR_IO_PENDING)
75 OnResolved(result);
76 }
77
78 private:
79 void OnResolved(int result) {
80 if (result < 0) {
81 SelfDestruct();
82 return;
83 }
84
85 host_socket_.reset(new net::TCPClientSocket(address_list_, NULL,
86 net::NetLog::Source()));
87 result = host_socket_->Connect(base::Bind(&SocketTunnel::OnConnected,
88 base::Unretained(this)));
89 if (result != net::ERR_IO_PENDING)
90 OnConnected(result);
91 }
92
93 ~SocketTunnel() {
94 if (host_socket_)
95 host_socket_->Disconnect();
96 if (remote_socket_)
97 remote_socket_->Disconnect();
98 }
99
100 void OnConnected(int result) {
101 if (result < 0) {
102 SelfDestruct();
103 return;
104 }
105
106 Pump(host_socket_.get(), remote_socket_.get());
107 Pump(remote_socket_.get(), host_socket_.get());
108 }
109
110 void Pump(net::StreamSocket* from, net::StreamSocket* to) {
111 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100112 int result = from->Read(
113 buffer.get(),
114 kBufferSize,
115 base::Bind(
116 &SocketTunnel::OnRead, base::Unretained(this), from, to, buffer));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100117 if (result != net::ERR_IO_PENDING)
118 OnRead(from, to, buffer, result);
119 }
120
121 void OnRead(net::StreamSocket* from,
122 net::StreamSocket* to,
123 scoped_refptr<net::IOBuffer> buffer,
124 int result) {
125 if (result <= 0) {
126 SelfDestruct();
127 return;
128 }
129
130 int total = result;
131 scoped_refptr<net::DrainableIOBuffer> drainable =
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100132 new net::DrainableIOBuffer(buffer.get(), total);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100133
134 ++pending_writes_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100135 result = to->Write(drainable.get(),
136 total,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100137 base::Bind(&SocketTunnel::OnWritten,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100138 base::Unretained(this),
139 drainable,
140 from,
141 to));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100142 if (result != net::ERR_IO_PENDING)
143 OnWritten(drainable, from, to, result);
144 }
145
146 void OnWritten(scoped_refptr<net::DrainableIOBuffer> drainable,
147 net::StreamSocket* from,
148 net::StreamSocket* to,
149 int result) {
150 --pending_writes_;
151 if (result < 0) {
152 SelfDestruct();
153 return;
154 }
155
156 drainable->DidConsume(result);
157 if (drainable->BytesRemaining() > 0) {
158 ++pending_writes_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100159 result = to->Write(drainable.get(),
160 drainable->BytesRemaining(),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100161 base::Bind(&SocketTunnel::OnWritten,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100162 base::Unretained(this),
163 drainable,
164 from,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100165 to));
166 if (result != net::ERR_IO_PENDING)
167 OnWritten(drainable, from, to, result);
168 return;
169 }
170
171 if (pending_destruction_) {
172 SelfDestruct();
173 return;
174 }
175 Pump(from, to);
176 }
177
178 void SelfDestruct() {
179 if (pending_writes_ > 0) {
180 pending_destruction_ = true;
181 return;
182 }
183 delete this;
184 }
185
186 std::string location_;
187 scoped_ptr<net::StreamSocket> remote_socket_;
188 scoped_ptr<net::StreamSocket> host_socket_;
189 scoped_ptr<net::HostResolver> host_resolver_;
190 net::AddressList address_list_;
191 int pending_writes_;
192 bool pending_destruction_;
193};
194
195} // namespace
196
Ben Murdoch2385ea32013-08-06 11:01:04 +0100197TetheringAdbFilter::TetheringAdbFilter(int adb_port,
198 const std::string& serial,
199 base::MessageLoop* adb_message_loop,
200 PrefService* pref_service,
201 scoped_refptr<AdbWebSocket> web_socket)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100202 : adb_port_(adb_port),
Ben Murdoch2385ea32013-08-06 11:01:04 +0100203 serial_(serial),
204 adb_message_loop_(adb_message_loop),
205 web_socket_(web_socket),
206 command_id_(0),
207 weak_factory_(this) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
209 pref_change_registrar_.Init(pref_service);
210
211 OnPrefsChange();
212
213 base::Closure pref_callback = base::Bind(
214 &TetheringAdbFilter::OnPrefsChange, base::Unretained(this));
215 pref_change_registrar_.Add(
216 prefs::kDevToolsPortForwardingEnabled, pref_callback);
217 pref_change_registrar_.Add(
218 prefs::kDevToolsPortForwardingConfig, pref_callback);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100219}
220
221TetheringAdbFilter::~TetheringAdbFilter() {
222}
223
Ben Murdoch2385ea32013-08-06 11:01:04 +0100224void TetheringAdbFilter::OnPrefsChange() {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226
227 ForwardingMap new_forwarding_map;
228
229 PrefService* pref_service = pref_change_registrar_.prefs();
230 bool enabled =
231 pref_service->GetBoolean(prefs::kDevToolsPortForwardingEnabled);
232 if (enabled) {
233 const DictionaryValue* dict =
234 pref_service->GetDictionary(prefs::kDevToolsPortForwardingConfig);
235 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
236 int port_num;
237 std::string location;
238 if (base::StringToInt(it.key(), &port_num) &&
239 dict->GetString(it.key(), &location))
240 new_forwarding_map[port_num] = location;
241 }
242 }
243
244 adb_message_loop_->PostTask(
245 FROM_HERE,
246 base::Bind(&TetheringAdbFilter::ChangeForwardingMap,
247 weak_factory_.GetWeakPtr(),
248 new_forwarding_map));
249}
250
251void TetheringAdbFilter::ChangeForwardingMap(ForwardingMap new_forwarding_map) {
252 DCHECK_EQ(base::MessageLoop::current(), adb_message_loop_);
253
254 SerializeChanges(kTetheringUnbind, new_forwarding_map, forwarding_map_);
255 SerializeChanges(kTetheringBind, forwarding_map_, new_forwarding_map);
256 forwarding_map_ = new_forwarding_map;
257}
258
259void TetheringAdbFilter::SerializeChanges(const std::string& method,
260 const ForwardingMap& old_map,
261 const ForwardingMap& new_map) {
262 for (ForwardingMap::const_iterator new_it(new_map.begin());
263 new_it != new_map.end(); ++new_it) {
264 int port = new_it->first;
265 const std::string& location = new_it->second;
266 ForwardingMap::const_iterator old_it = old_map.find(port);
267 if (old_it != old_map.end() && old_it->second == location)
268 continue; // The port points to the same location in both configs, skip.
269
270 SendCommand(method, port);
271 }
272}
273
274void TetheringAdbFilter::SendCommand(const std::string& method, int port) {
Ben Murdoch2385ea32013-08-06 11:01:04 +0100275 base::DictionaryValue params;
276 params.SetInteger(kPortAttribute, port);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100277 DevToolsProtocol::Command command(++command_id_, method, &params);
278 web_socket_->SendFrameOnHandlerThread(command.Serialize());
Ben Murdoch2385ea32013-08-06 11:01:04 +0100279}
280
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100281bool TetheringAdbFilter::ProcessIncomingMessage(const std::string& message) {
Ben Murdoch2385ea32013-08-06 11:01:04 +0100282 DCHECK_EQ(base::MessageLoop::current(), adb_message_loop_);
283
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100284 // Only parse messages that might be Tethering.accepted event.
285 if (message.length() > 200 ||
286 message.find(kTetheringAccepted) == std::string::npos)
287 return false;
288
Ben Murdochbb1529c2013-08-08 10:24:53 +0100289 scoped_ptr<DevToolsProtocol::Notification> notification(
290 DevToolsProtocol::ParseNotification(message));
291 if (!notification)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100292 return false;
293
Ben Murdochbb1529c2013-08-08 10:24:53 +0100294 if (notification->method() != kTetheringAccepted)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100295 return false;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100296
Ben Murdochbb1529c2013-08-08 10:24:53 +0100297 DictionaryValue* params = notification->params();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100298 if (!params)
299 return false;
300
301 int port;
302 std::string connection_id;
303 if (!params->GetInteger(kPortAttribute, &port) ||
304 !params->GetString(kConnectionIdAttribute, &connection_id))
305 return false;
306
Ben Murdoch2385ea32013-08-06 11:01:04 +0100307 std::map<int, std::string>::iterator it = forwarding_map_.find(port);
308 if (it == forwarding_map_.end())
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100309 return false;
310
311 std::string location = it->second;
312
313 SocketTunnel* tunnel = new SocketTunnel(location);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100314 std::string command = base::StringPrintf(kLocalAbstractCommand,
315 connection_id.c_str());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100316 AdbClientSocket::TransportQuery(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100317 adb_port_, serial_, command,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100318 base::Bind(&SocketTunnel::Start, base::Unretained(tunnel)));
319 return true;
320}
321
Ben Murdoch2385ea32013-08-06 11:01:04 +0100322class PortForwardingController::Connection : public AdbWebSocket::Delegate {
323 public:
324 Connection(
325 Registry* registry,
326 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
327 base::MessageLoop* adb_message_loop,
328 PrefService* pref_service);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100329
Ben Murdoch2385ea32013-08-06 11:01:04 +0100330 void Shutdown();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100331
Ben Murdoch2385ea32013-08-06 11:01:04 +0100332 private:
333 virtual ~Connection();
334
335 virtual void OnSocketOpened() OVERRIDE;
336 virtual void OnFrameRead(const std::string& message) OVERRIDE;
337 virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
338 virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE;
339
340 Registry* registry_;
341 const std::string serial_;
342 base::MessageLoop* adb_message_loop_;
343 PrefService* pref_service_;
344
345 scoped_ptr<TetheringAdbFilter> tethering_adb_filter_;
346 scoped_refptr<AdbWebSocket> web_socket_;
347};
348
349PortForwardingController::Connection::Connection(
350 Registry* registry,
351 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
352 base::MessageLoop* adb_message_loop,
353 PrefService* pref_service)
354 : registry_(registry),
355 serial_(device->serial()),
356 adb_message_loop_(adb_message_loop),
357 pref_service_(pref_service) {
358 (*registry_)[serial_] = this;
359 web_socket_ = new AdbWebSocket(
360 device, kDevToolsRemoteSocketName, kDevToolsRemoteBrowserTarget,
361 adb_message_loop_, this);
362}
363
364void PortForwardingController::Connection::Shutdown() {
365 registry_ = NULL;
366 // This will have no effect if the socket is not connected yet.
367 web_socket_->Disconnect();
368}
369
370PortForwardingController::Connection::~Connection() {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
372 if (registry_) {
373 DCHECK(registry_->find(serial_) != registry_->end());
374 registry_->erase(serial_);
375 }
376}
377
378void PortForwardingController::Connection::OnSocketOpened() {
379 if (!registry_) {
380 // Socket was created after Shutdown was called. Disconnect immediately.
381 web_socket_->Disconnect();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100382 return;
Ben Murdoch2385ea32013-08-06 11:01:04 +0100383 }
384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
385 tethering_adb_filter_.reset(new TetheringAdbFilter(
386 kAdbPort, serial_, adb_message_loop_, pref_service_, web_socket_));
387}
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100388
Ben Murdoch2385ea32013-08-06 11:01:04 +0100389void PortForwardingController::Connection::OnFrameRead(
390 const std::string& message) {
391}
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100392
Ben Murdoch2385ea32013-08-06 11:01:04 +0100393void PortForwardingController::Connection::OnSocketClosed(
394 bool closed_by_device) {
395 delete this;
396}
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100397
Ben Murdoch2385ea32013-08-06 11:01:04 +0100398bool PortForwardingController::Connection::ProcessIncomingMessage(
399 const std::string& message) {
400 return tethering_adb_filter_->ProcessIncomingMessage(message);
401}
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100402
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100403
Ben Murdoch2385ea32013-08-06 11:01:04 +0100404PortForwardingController::PortForwardingController(
405 base::MessageLoop* adb_message_loop,
406 PrefService* pref_service)
407 : adb_message_loop_(adb_message_loop),
408 pref_service_(pref_service) {
409}
410
411PortForwardingController::~PortForwardingController() {
412 for (Registry::iterator it = registry_.begin(); it != registry_.end(); ++it)
413 it->second->Shutdown();
414}
415
416void PortForwardingController::UpdateDeviceList(
417 const DevToolsAdbBridge::RemoteDevices& devices) {
418 for (DevToolsAdbBridge::RemoteDevices::const_iterator it = devices.begin();
419 it != devices.end(); ++it) {
420 if (registry_.find((*it)->serial()) == registry_.end()) {
421 // Will delete itself when disconnected.
422 new Connection(
423 &registry_, (*it)->device(), adb_message_loop_, pref_service_);
424 }
425 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100426}