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"
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"
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
{
37 SocketPump(DevToolsHttpHandlerDelegate
* delegate
,
38 net::StreamSocket
* client_socket
)
39 : client_socket_(client_socket
),
42 pending_destruction_(false) {
46 std::string channel_name
;
47 server_socket_
= delegate_
->CreateSocketForTethering(this, &channel_name
);
48 if (!server_socket_
.get() || channel_name
.empty())
53 virtual ~SocketPump() { }
56 virtual void DidAccept(net::StreamListenSocket
* server
,
57 scoped_ptr
<net::StreamListenSocket
> socket
) OVERRIDE
{
58 if (accepted_socket_
.get())
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(
69 base::Bind(&SocketPump::OnClientRead
, base::Unretained(this)));
70 if (result
!= net::ERR_IO_PENDING
)
74 virtual void DidRead(net::StreamListenSocket
* socket
,
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())
87 virtual void DidClose(net::StreamListenSocket
* socket
) OVERRIDE
{
91 void OnClientRead(int result
) {
97 accepted_socket_
->Send(buffer_
->data(), result
);
98 result
= client_socket_
->Read(
101 base::Bind(&SocketPump::OnClientRead
, base::Unretained(this)));
102 if (result
!= net::ERR_IO_PENDING
)
103 OnClientRead(result
);
106 void OnClientWrite(int result
) {
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_
)
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(
130 base::Bind(&SocketPump::OnClientWrite
, base::Unretained(this)));
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
);
146 void SelfDestruct() {
147 if (wire_buffer_
.get() && wire_buffer_
->offset() != wire_buffer_size_
) {
148 pending_destruction_
= true;
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();
170 !params
->GetInteger(paramName
, &port
) ||
171 port
< kMinTetheringPort
|| port
> kMaxTetheringPort
)
178 typedef base::Callback
<void(int, const std::string
&)> AcceptedCallback
;
180 BoundSocket(AcceptedCallback accepted_callback
,
181 DevToolsHttpHandlerDelegate
* delegate
)
182 : accepted_callback_(accepted_callback
),
184 socket_(new net::TCPServerSocket(NULL
, net::NetLog::Source())),
188 virtual ~BoundSocket() {
191 bool Listen(int port
) {
193 net::IPAddressNumber ip_number
;
194 if (!net::ParseIPLiteralToNumber(kLocalhost
, &ip_number
))
197 net::IPEndPoint
end_point(ip_number
, port
);
198 int result
= socket_
->Listen(end_point
, kListenBacklog
);
202 net::IPEndPoint local_address
;
203 result
= socket_
->GetLocalAddress(&local_address
);
212 typedef std::map
<net::IPEndPoint
, net::StreamSocket
*> AcceptedSocketsMap
;
216 int result
= socket_
->Accept(
218 base::Bind(&BoundSocket::OnAccepted
, base::Unretained(this)));
219 if (result
== net::ERR_IO_PENDING
)
222 HandleAcceptResult(result
);
226 void OnAccepted(int result
) {
227 HandleAcceptResult(result
);
228 if (result
== net::OK
)
232 void HandleAcceptResult(int result
) {
233 if (result
!= net::OK
)
236 SocketPump
* pump
= new SocketPump(delegate_
, accept_socket_
.release());
237 std::string name
= pump
->Init();
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_
;
251 // TetheringHandler::TetheringImpl -------------------------------------------
253 class TetheringHandler::TetheringImpl
{
256 base::WeakPtr
<TetheringHandler
> handler
,
257 DevToolsHttpHandlerDelegate
* delegate
);
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
);
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
)
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
);
291 SendAsyncResponse(command
->InvalidParamResponse(portParamName
));
295 if (bound_sockets_
.find(port
) != bound_sockets_
.end()) {
296 SendAsyncResponse(command
->InternalErrorResponse("Port already bound"));
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"));
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
);
317 SendAsyncResponse(command
->InvalidParamResponse(portParamName
));
321 BoundSockets::iterator it
= bound_sockets_
.find(port
);
322 if (it
== bound_sockets_
.end()) {
323 SendAsyncResponse(command
->InternalErrorResponse("Port is not bound"));
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(
337 base::Bind(&TetheringHandler::Accepted
, handler_
, port
, name
));
340 void TetheringHandler::TetheringImpl::SendAsyncResponse(
341 scoped_refptr
<DevToolsProtocol::Response
> response
) {
342 BrowserThread::PostTask(
345 base::Bind(&TetheringHandler::SendAsyncResponse
, handler_
, response
));
348 // TetheringHandler ----------------------------------------------------------
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
),
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() {
370 message_loop_proxy_
->DeleteSoon(FROM_HERE
, impl_
);
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() {
388 impl_
= new TetheringImpl(weak_factory_
.GetWeakPtr(), delegate_
);
392 scoped_refptr
<DevToolsProtocol::Response
>
393 TetheringHandler::OnBind(scoped_refptr
<DevToolsProtocol::Command
> command
) {
395 return command
->ServerErrorResponse(
396 "Tethering is used by another connection");
399 message_loop_proxy_
->PostTask(
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
) {
408 return command
->ServerErrorResponse(
409 "Tethering is used by another connection");
412 message_loop_proxy_
->PostTask(
414 base::Bind(&TetheringImpl::Unbind
, base::Unretained(impl_
), command
));
415 return command
->AsyncResponsePromise();
418 } // namespace content