[DevTools] Make TetheringHandler operate on UI thread.
[chromium-blink-merge.git] / content / browser / devtools / tethering_handler.cc
blob8016661cd118896429077b55af44135584c8208c
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.
5 #include "content/browser/devtools/tethering_handler.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/stl_util.h"
10 #include "base/values.h"
11 #include "content/browser/devtools/devtools_http_handler_impl.h"
12 #include "content/browser/devtools/devtools_protocol_constants.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/devtools_http_handler_delegate.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/ip_endpoint.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/net_log.h"
19 #include "net/socket/stream_listen_socket.h"
20 #include "net/socket/stream_socket.h"
21 #include "net/socket/tcp_server_socket.h"
23 namespace content {
25 namespace {
27 const char kLocalhost[] = "127.0.0.1";
29 const int kListenBacklog = 5;
30 const int kBufferSize = 16 * 1024;
32 const int kMinTetheringPort = 1024;
33 const int kMaxTetheringPort = 32767;
35 class SocketPump : public net::StreamListenSocket::Delegate {
36 public:
37 SocketPump(DevToolsHttpHandlerDelegate* delegate,
38 net::StreamSocket* client_socket)
39 : client_socket_(client_socket),
40 delegate_(delegate),
41 wire_buffer_size_(0),
42 pending_destruction_(false) {
45 std::string Init() {
46 std::string channel_name;
47 server_socket_ = delegate_->CreateSocketForTethering(this, &channel_name);
48 if (!server_socket_.get() || channel_name.empty())
49 SelfDestruct();
50 return channel_name;
53 virtual ~SocketPump() { }
55 private:
56 virtual void DidAccept(net::StreamListenSocket* server,
57 scoped_ptr<net::StreamListenSocket> socket) OVERRIDE {
58 if (accepted_socket_.get())
59 return;
61 buffer_ = new net::IOBuffer(kBufferSize);
62 wire_buffer_ = new net::GrowableIOBuffer();
63 wire_buffer_->SetCapacity(kBufferSize);
65 accepted_socket_ = socket.Pass();
66 int result = client_socket_->Read(
67 buffer_.get(),
68 kBufferSize,
69 base::Bind(&SocketPump::OnClientRead, base::Unretained(this)));
70 if (result != net::ERR_IO_PENDING)
71 OnClientRead(result);
74 virtual void DidRead(net::StreamListenSocket* socket,
75 const char* data,
76 int len) OVERRIDE {
77 int old_size = wire_buffer_size_;
78 wire_buffer_size_ += len;
79 while (wire_buffer_->capacity() < wire_buffer_size_)
80 wire_buffer_->SetCapacity(wire_buffer_->capacity() * 2);
81 memcpy(wire_buffer_->StartOfBuffer() + old_size, data, len);
82 if (old_size != wire_buffer_->offset())
83 return;
84 OnClientWrite(0);
87 virtual void DidClose(net::StreamListenSocket* socket) OVERRIDE {
88 SelfDestruct();
91 void OnClientRead(int result) {
92 if (result <= 0) {
93 SelfDestruct();
94 return;
97 accepted_socket_->Send(buffer_->data(), result);
98 result = client_socket_->Read(
99 buffer_.get(),
100 kBufferSize,
101 base::Bind(&SocketPump::OnClientRead, base::Unretained(this)));
102 if (result != net::ERR_IO_PENDING)
103 OnClientRead(result);
106 void OnClientWrite(int result) {
107 if (result < 0) {
108 SelfDestruct();
109 return;
112 wire_buffer_->set_offset(wire_buffer_->offset() + result);
114 int remaining = wire_buffer_size_ - wire_buffer_->offset();
115 if (remaining == 0) {
116 if (pending_destruction_)
117 SelfDestruct();
118 return;
122 if (remaining > kBufferSize)
123 remaining = kBufferSize;
125 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(remaining);
126 memcpy(buffer->data(), wire_buffer_->data(), remaining);
127 result = client_socket_->Write(
128 buffer.get(),
129 remaining,
130 base::Bind(&SocketPump::OnClientWrite, base::Unretained(this)));
132 // Shrink buffer
133 int offset = wire_buffer_->offset();
134 if (offset > kBufferSize) {
135 memcpy(wire_buffer_->StartOfBuffer(), wire_buffer_->data(),
136 wire_buffer_size_ - offset);
137 wire_buffer_size_ -= offset;
138 wire_buffer_->set_offset(0);
141 if (result != net::ERR_IO_PENDING)
142 OnClientWrite(result);
143 return;
146 void SelfDestruct() {
147 if (wire_buffer_.get() && wire_buffer_->offset() != wire_buffer_size_) {
148 pending_destruction_ = true;
149 return;
151 delete this;
154 private:
155 scoped_ptr<net::StreamSocket> client_socket_;
156 scoped_ptr<net::StreamListenSocket> server_socket_;
157 scoped_ptr<net::StreamListenSocket> accepted_socket_;
158 scoped_refptr<net::IOBuffer> buffer_;
159 scoped_refptr<net::GrowableIOBuffer> wire_buffer_;
160 DevToolsHttpHandlerDelegate* delegate_;
161 int wire_buffer_size_;
162 bool pending_destruction_;
165 static int GetPort(scoped_refptr<DevToolsProtocol::Command> command,
166 const std::string& paramName) {
167 base::DictionaryValue* params = command->params();
168 int port = 0;
169 if (!params ||
170 !params->GetInteger(paramName, &port) ||
171 port < kMinTetheringPort || port > kMaxTetheringPort)
172 return 0;
173 return port;
176 class BoundSocket {
177 public:
178 typedef base::Callback<void(int, const std::string&)> AcceptedCallback;
180 BoundSocket(AcceptedCallback accepted_callback,
181 DevToolsHttpHandlerDelegate* delegate)
182 : accepted_callback_(accepted_callback),
183 delegate_(delegate),
184 socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
185 port_(0) {
188 virtual ~BoundSocket() {
191 bool Listen(int port) {
192 port_ = port;
193 net::IPAddressNumber ip_number;
194 if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
195 return false;
197 net::IPEndPoint end_point(ip_number, port);
198 int result = socket_->Listen(end_point, kListenBacklog);
199 if (result < 0)
200 return false;
202 net::IPEndPoint local_address;
203 result = socket_->GetLocalAddress(&local_address);
204 if (result < 0)
205 return false;
207 DoAccept();
208 return true;
211 private:
212 typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
214 void DoAccept() {
215 while (true) {
216 int result = socket_->Accept(
217 &accept_socket_,
218 base::Bind(&BoundSocket::OnAccepted, base::Unretained(this)));
219 if (result == net::ERR_IO_PENDING)
220 break;
221 else
222 HandleAcceptResult(result);
226 void OnAccepted(int result) {
227 HandleAcceptResult(result);
228 if (result == net::OK)
229 DoAccept();
232 void HandleAcceptResult(int result) {
233 if (result != net::OK)
234 return;
236 SocketPump* pump = new SocketPump(delegate_, accept_socket_.release());
237 std::string name = pump->Init();
238 if (!name.empty())
239 accepted_callback_.Run(port_, name);
242 AcceptedCallback accepted_callback_;
243 DevToolsHttpHandlerDelegate* delegate_;
244 scoped_ptr<net::ServerSocket> socket_;
245 scoped_ptr<net::StreamSocket> accept_socket_;
246 int port_;
249 } // namespace
251 // TetheringHandler::TetheringImpl -------------------------------------------
253 class TetheringHandler::TetheringImpl {
254 public:
255 TetheringImpl(
256 base::WeakPtr<TetheringHandler> handler,
257 DevToolsHttpHandlerDelegate* delegate);
258 ~TetheringImpl();
260 void Bind(scoped_refptr<DevToolsProtocol::Command> command);
261 void Unbind(scoped_refptr<DevToolsProtocol::Command> command);
262 void Accepted(int port, const std::string& name);
264 private:
265 void SendAsyncResponse(scoped_refptr<DevToolsProtocol::Response> response);
267 base::WeakPtr<TetheringHandler> handler_;
268 DevToolsHttpHandlerDelegate* delegate_;
270 typedef std::map<int, BoundSocket*> BoundSockets;
271 BoundSockets bound_sockets_;
274 TetheringHandler::TetheringImpl::TetheringImpl(
275 base::WeakPtr<TetheringHandler> handler,
276 DevToolsHttpHandlerDelegate* delegate)
277 : handler_(handler),
278 delegate_(delegate) {
281 TetheringHandler::TetheringImpl::~TetheringImpl() {
282 STLDeleteContainerPairSecondPointers(bound_sockets_.begin(),
283 bound_sockets_.end());
286 void TetheringHandler::TetheringImpl::Bind(
287 scoped_refptr<DevToolsProtocol::Command> command) {
288 const std::string& portParamName = devtools::Tethering::bind::kParamPort;
289 int port = GetPort(command, portParamName);
290 if (port == 0) {
291 SendAsyncResponse(command->InvalidParamResponse(portParamName));
292 return;
295 if (bound_sockets_.find(port) != bound_sockets_.end()) {
296 SendAsyncResponse(command->InternalErrorResponse("Port already bound"));
297 return;
300 BoundSocket::AcceptedCallback callback = base::Bind(
301 &TetheringHandler::TetheringImpl::Accepted, base::Unretained(this));
302 scoped_ptr<BoundSocket> bound_socket(new BoundSocket(callback, delegate_));
303 if (!bound_socket->Listen(port)) {
304 SendAsyncResponse(command->InternalErrorResponse("Could not bind port"));
305 return;
308 bound_sockets_[port] = bound_socket.release();
309 SendAsyncResponse(command->SuccessResponse(NULL));
312 void TetheringHandler::TetheringImpl::Unbind(
313 scoped_refptr<DevToolsProtocol::Command> command) {
314 const std::string& portParamName = devtools::Tethering::unbind::kParamPort;
315 int port = GetPort(command, portParamName);
316 if (port == 0) {
317 SendAsyncResponse(command->InvalidParamResponse(portParamName));
318 return;
321 BoundSockets::iterator it = bound_sockets_.find(port);
322 if (it == bound_sockets_.end()) {
323 SendAsyncResponse(command->InternalErrorResponse("Port is not bound"));
324 return;
327 delete it->second;
328 bound_sockets_.erase(it);
329 SendAsyncResponse(command->SuccessResponse(NULL));
332 void TetheringHandler::TetheringImpl::Accepted(
333 int port, const std::string& name) {
334 BrowserThread::PostTask(
335 BrowserThread::UI,
336 FROM_HERE,
337 base::Bind(&TetheringHandler::Accepted, handler_, port, name));
340 void TetheringHandler::TetheringImpl::SendAsyncResponse(
341 scoped_refptr<DevToolsProtocol::Response> response) {
342 BrowserThread::PostTask(
343 BrowserThread::UI,
344 FROM_HERE,
345 base::Bind(&TetheringHandler::SendAsyncResponse, handler_, response));
348 // TetheringHandler ----------------------------------------------------------
350 // static
351 TetheringHandler::TetheringImpl* TetheringHandler::impl_ = nullptr;
353 TetheringHandler::TetheringHandler(
354 DevToolsHttpHandlerDelegate* delegate,
355 scoped_refptr<base::MessageLoopProxy> message_loop_proxy)
356 : delegate_(delegate),
357 message_loop_proxy_(message_loop_proxy),
358 is_active_(false),
359 weak_factory_(this) {
360 RegisterCommandHandler(devtools::Tethering::bind::kName,
361 base::Bind(&TetheringHandler::OnBind,
362 base::Unretained(this)));
363 RegisterCommandHandler(devtools::Tethering::unbind::kName,
364 base::Bind(&TetheringHandler::OnUnbind,
365 base::Unretained(this)));
368 TetheringHandler::~TetheringHandler() {
369 if (is_active_) {
370 message_loop_proxy_->DeleteSoon(FROM_HERE, impl_);
371 impl_ = nullptr;
375 void TetheringHandler::Accepted(int port, const std::string& name) {
376 base::DictionaryValue* params = new base::DictionaryValue();
377 params->SetInteger(devtools::Tethering::accepted::kParamPort, port);
378 params->SetString(devtools::Tethering::accepted::kParamConnectionId, name);
379 SendNotification(devtools::Tethering::accepted::kName, params);
382 bool TetheringHandler::Activate() {
383 if (is_active_)
384 return true;
385 if (impl_)
386 return false;
387 is_active_ = true;
388 impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), delegate_);
389 return true;
392 scoped_refptr<DevToolsProtocol::Response>
393 TetheringHandler::OnBind(scoped_refptr<DevToolsProtocol::Command> command) {
394 if (!Activate()) {
395 return command->ServerErrorResponse(
396 "Tethering is used by another connection");
398 DCHECK(impl_);
399 message_loop_proxy_->PostTask(
400 FROM_HERE,
401 base::Bind(&TetheringImpl::Bind, base::Unretained(impl_), command));
402 return command->AsyncResponsePromise();
405 scoped_refptr<DevToolsProtocol::Response>
406 TetheringHandler::OnUnbind(scoped_refptr<DevToolsProtocol::Command> command) {
407 if (!Activate()) {
408 return command->ServerErrorResponse(
409 "Tethering is used by another connection");
411 DCHECK(impl_);
412 message_loop_proxy_->PostTask(
413 FROM_HERE,
414 base::Bind(&TetheringImpl::Unbind, base::Unretained(impl_), command));
415 return command->AsyncResponsePromise();
418 } // namespace content