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/server_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;
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(&channel_name
);
48 if (!server_socket_
.get() || channel_name
.empty())
51 int result
= server_socket_
->Accept(
53 base::Bind(&SocketPump::OnAccepted
, base::Unretained(this)));
54 if (result
!= net::ERR_IO_PENDING
)
60 void OnAccepted(int result
) {
66 ++pending_writes_
; // avoid SelfDestruct in first Pump
67 Pump(client_socket_
.get(), accepted_socket_
.get());
69 if (pending_destruction_
) {
72 Pump(accepted_socket_
.get(), client_socket_
.get());
76 void Pump(net::StreamSocket
* from
, net::StreamSocket
* to
) {
77 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(kBufferSize
);
78 int result
= from
->Read(
82 &SocketPump::OnRead
, base::Unretained(this), from
, to
, buffer
));
83 if (result
!= net::ERR_IO_PENDING
)
84 OnRead(from
, to
, buffer
, result
);
87 void OnRead(net::StreamSocket
* from
,
88 net::StreamSocket
* to
,
89 scoped_refptr
<net::IOBuffer
> buffer
,
97 scoped_refptr
<net::DrainableIOBuffer
> drainable
=
98 new net::DrainableIOBuffer(buffer
.get(), total
);
101 result
= to
->Write(drainable
.get(),
103 base::Bind(&SocketPump::OnWritten
,
104 base::Unretained(this),
108 if (result
!= net::ERR_IO_PENDING
)
109 OnWritten(drainable
, from
, to
, result
);
112 void OnWritten(scoped_refptr
<net::DrainableIOBuffer
> drainable
,
113 net::StreamSocket
* from
,
114 net::StreamSocket
* to
,
122 drainable
->DidConsume(result
);
123 if (drainable
->BytesRemaining() > 0) {
125 result
= to
->Write(drainable
.get(),
126 drainable
->BytesRemaining(),
127 base::Bind(&SocketPump::OnWritten
,
128 base::Unretained(this),
132 if (result
!= net::ERR_IO_PENDING
)
133 OnWritten(drainable
, from
, to
, result
);
137 if (pending_destruction_
) {
144 void SelfDestruct() {
145 if (pending_writes_
> 0) {
146 pending_destruction_
= true;
154 scoped_ptr
<net::StreamSocket
> client_socket_
;
155 scoped_ptr
<net::ServerSocket
> server_socket_
;
156 scoped_ptr
<net::StreamSocket
> accepted_socket_
;
157 DevToolsHttpHandlerDelegate
* delegate_
;
159 bool pending_destruction_
;
162 static int GetPort(scoped_refptr
<DevToolsProtocol::Command
> command
,
163 const std::string
& paramName
) {
164 base::DictionaryValue
* params
= command
->params();
167 !params
->GetInteger(paramName
, &port
) ||
168 port
< kMinTetheringPort
|| port
> kMaxTetheringPort
)
175 typedef base::Callback
<void(int, const std::string
&)> AcceptedCallback
;
177 BoundSocket(AcceptedCallback accepted_callback
,
178 DevToolsHttpHandlerDelegate
* delegate
)
179 : accepted_callback_(accepted_callback
),
181 socket_(new net::TCPServerSocket(NULL
, net::NetLog::Source())),
185 virtual ~BoundSocket() {
188 bool Listen(int port
) {
190 net::IPAddressNumber ip_number
;
191 if (!net::ParseIPLiteralToNumber(kLocalhost
, &ip_number
))
194 net::IPEndPoint
end_point(ip_number
, port
);
195 int result
= socket_
->Listen(end_point
, kListenBacklog
);
199 net::IPEndPoint local_address
;
200 result
= socket_
->GetLocalAddress(&local_address
);
209 typedef std::map
<net::IPEndPoint
, net::StreamSocket
*> AcceptedSocketsMap
;
213 int result
= socket_
->Accept(
215 base::Bind(&BoundSocket::OnAccepted
, base::Unretained(this)));
216 if (result
== net::ERR_IO_PENDING
)
219 HandleAcceptResult(result
);
223 void OnAccepted(int result
) {
224 HandleAcceptResult(result
);
225 if (result
== net::OK
)
229 void HandleAcceptResult(int result
) {
230 if (result
!= net::OK
)
233 SocketPump
* pump
= new SocketPump(delegate_
, accept_socket_
.release());
234 std::string name
= pump
->Init();
236 accepted_callback_
.Run(port_
, name
);
239 AcceptedCallback accepted_callback_
;
240 DevToolsHttpHandlerDelegate
* delegate_
;
241 scoped_ptr
<net::ServerSocket
> socket_
;
242 scoped_ptr
<net::StreamSocket
> accept_socket_
;
248 // TetheringHandler::TetheringImpl -------------------------------------------
250 class TetheringHandler::TetheringImpl
{
253 base::WeakPtr
<TetheringHandler
> handler
,
254 DevToolsHttpHandlerDelegate
* delegate
);
257 void Bind(scoped_refptr
<DevToolsProtocol::Command
> command
, int port
);
258 void Unbind(scoped_refptr
<DevToolsProtocol::Command
> command
, int port
);
259 void Accepted(int port
, const std::string
& name
);
262 void SendInternalError(scoped_refptr
<DevToolsProtocol::Command
> command
,
263 const std::string
& message
);
265 base::WeakPtr
<TetheringHandler
> handler_
;
266 DevToolsHttpHandlerDelegate
* delegate_
;
268 typedef std::map
<int, BoundSocket
*> BoundSockets
;
269 BoundSockets bound_sockets_
;
272 TetheringHandler::TetheringImpl::TetheringImpl(
273 base::WeakPtr
<TetheringHandler
> handler
,
274 DevToolsHttpHandlerDelegate
* delegate
)
276 delegate_(delegate
) {
279 TetheringHandler::TetheringImpl::~TetheringImpl() {
280 STLDeleteContainerPairSecondPointers(bound_sockets_
.begin(),
281 bound_sockets_
.end());
284 void TetheringHandler::TetheringImpl::Bind(
285 scoped_refptr
<DevToolsProtocol::Command
> command
, int port
) {
286 if (bound_sockets_
.find(port
) != bound_sockets_
.end()) {
287 SendInternalError(command
, "Port already bound");
291 BoundSocket::AcceptedCallback callback
= base::Bind(
292 &TetheringHandler::TetheringImpl::Accepted
, base::Unretained(this));
293 scoped_ptr
<BoundSocket
> bound_socket(new BoundSocket(callback
, delegate_
));
294 if (!bound_socket
->Listen(port
)) {
295 SendInternalError(command
, "Could not bind port");
299 bound_sockets_
[port
] = bound_socket
.release();
300 BrowserThread::PostTask(
303 base::Bind(&TetheringHandler::SendBindSuccess
, handler_
, command
));
306 void TetheringHandler::TetheringImpl::Unbind(
307 scoped_refptr
<DevToolsProtocol::Command
> command
, int port
) {
309 BoundSockets::iterator it
= bound_sockets_
.find(port
);
310 if (it
== bound_sockets_
.end()) {
311 SendInternalError(command
, "Port is not bound");
316 bound_sockets_
.erase(it
);
317 BrowserThread::PostTask(
320 base::Bind(&TetheringHandler::SendUnbindSuccess
, handler_
, command
));
323 void TetheringHandler::TetheringImpl::Accepted(
324 int port
, const std::string
& name
) {
325 BrowserThread::PostTask(
328 base::Bind(&TetheringHandler::Accepted
, handler_
, port
, name
));
331 void TetheringHandler::TetheringImpl::SendInternalError(
332 scoped_refptr
<DevToolsProtocol::Command
> command
,
333 const std::string
& message
) {
334 BrowserThread::PostTask(
337 base::Bind(&TetheringHandler::SendInternalError
, handler_
,
342 // TetheringHandler ----------------------------------------------------------
345 TetheringHandler::TetheringImpl
* TetheringHandler::impl_
= nullptr;
347 TetheringHandler::TetheringHandler(
348 DevToolsHttpHandlerDelegate
* delegate
,
349 scoped_refptr
<base::MessageLoopProxy
> message_loop_proxy
)
350 : delegate_(delegate
),
351 message_loop_proxy_(message_loop_proxy
),
353 weak_factory_(this) {
354 RegisterCommandHandler(devtools::Tethering::bind::kName
,
355 base::Bind(&TetheringHandler::OnBind
,
356 base::Unretained(this)));
357 RegisterCommandHandler(devtools::Tethering::unbind::kName
,
358 base::Bind(&TetheringHandler::OnUnbind
,
359 base::Unretained(this)));
362 TetheringHandler::~TetheringHandler() {
364 message_loop_proxy_
->DeleteSoon(FROM_HERE
, impl_
);
369 void TetheringHandler::Accepted(int port
, const std::string
& name
) {
370 base::DictionaryValue
* params
= new base::DictionaryValue();
371 params
->SetInteger(devtools::Tethering::accepted::kParamPort
, port
);
372 params
->SetString(devtools::Tethering::accepted::kParamConnectionId
, name
);
373 SendNotification(devtools::Tethering::accepted::kName
, params
);
376 bool TetheringHandler::Activate() {
382 impl_
= new TetheringImpl(weak_factory_
.GetWeakPtr(), delegate_
);
386 scoped_refptr
<DevToolsProtocol::Response
>
387 TetheringHandler::OnBind(scoped_refptr
<DevToolsProtocol::Command
> command
) {
388 const std::string
& portParamName
= devtools::Tethering::bind::kParamPort
;
389 int port
= GetPort(command
, portParamName
);
391 return command
->InvalidParamResponse(portParamName
);
394 return command
->ServerErrorResponse(
395 "Tethering is used by another connection");
398 message_loop_proxy_
->PostTask(
400 base::Bind(&TetheringImpl::Bind
, base::Unretained(impl_
),
402 return command
->AsyncResponsePromise();
405 scoped_refptr
<DevToolsProtocol::Response
>
406 TetheringHandler::OnUnbind(scoped_refptr
<DevToolsProtocol::Command
> command
) {
407 const std::string
& portParamName
= devtools::Tethering::unbind::kParamPort
;
408 int port
= GetPort(command
, portParamName
);
410 return command
->InvalidParamResponse(portParamName
);
413 return command
->ServerErrorResponse(
414 "Tethering is used by another connection");
417 message_loop_proxy_
->PostTask(
419 base::Bind(&TetheringImpl::Unbind
, base::Unretained(impl_
),
421 return command
->AsyncResponsePromise();
424 void TetheringHandler::SendBindSuccess(
425 scoped_refptr
<DevToolsProtocol::Command
> command
) {
426 SendAsyncResponse(command
->SuccessResponse(nullptr));
429 void TetheringHandler::SendUnbindSuccess(
430 scoped_refptr
<DevToolsProtocol::Command
> command
) {
431 SendAsyncResponse(command
->SuccessResponse(nullptr));
434 void TetheringHandler::SendInternalError(
435 scoped_refptr
<DevToolsProtocol::Command
> command
,
436 const std::string
& message
) {
437 SendAsyncResponse(command
->InternalErrorResponse(message
));
440 } // namespace content