1 // Copyright 2014 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/protocol/tethering_handler.h"
7 #include "base/stl_util.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "net/socket/server_socket.h"
12 #include "net/socket/stream_socket.h"
13 #include "net/socket/tcp_server_socket.h"
21 const char kLocalhost
[] = "127.0.0.1";
23 const int kListenBacklog
= 5;
24 const int kBufferSize
= 16 * 1024;
26 const int kMinTetheringPort
= 1024;
27 const int kMaxTetheringPort
= 32767;
29 using Response
= DevToolsProtocolClient::Response
;
30 using CreateServerSocketCallback
=
31 base::Callback
<scoped_ptr
<net::ServerSocket
>(std::string
*)>;
35 SocketPump(net::StreamSocket
* client_socket
)
36 : client_socket_(client_socket
),
38 pending_destruction_(false) {
41 std::string
Init(const CreateServerSocketCallback
& socket_callback
) {
42 std::string channel_name
;
43 server_socket_
= socket_callback
.Run(&channel_name
);
44 if (!server_socket_
.get() || channel_name
.empty())
47 int result
= server_socket_
->Accept(
49 base::Bind(&SocketPump::OnAccepted
, base::Unretained(this)));
50 if (result
!= net::ERR_IO_PENDING
)
56 void OnAccepted(int result
) {
62 ++pending_writes_
; // avoid SelfDestruct in first Pump
63 Pump(client_socket_
.get(), accepted_socket_
.get());
65 if (pending_destruction_
) {
68 Pump(accepted_socket_
.get(), client_socket_
.get());
72 void Pump(net::StreamSocket
* from
, net::StreamSocket
* to
) {
73 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(kBufferSize
);
74 int result
= from
->Read(
78 &SocketPump::OnRead
, base::Unretained(this), from
, to
, buffer
));
79 if (result
!= net::ERR_IO_PENDING
)
80 OnRead(from
, to
, buffer
, result
);
83 void OnRead(net::StreamSocket
* from
,
84 net::StreamSocket
* to
,
85 scoped_refptr
<net::IOBuffer
> buffer
,
93 scoped_refptr
<net::DrainableIOBuffer
> drainable
=
94 new net::DrainableIOBuffer(buffer
.get(), total
);
97 result
= to
->Write(drainable
.get(),
99 base::Bind(&SocketPump::OnWritten
,
100 base::Unretained(this),
104 if (result
!= net::ERR_IO_PENDING
)
105 OnWritten(drainable
, from
, to
, result
);
108 void OnWritten(scoped_refptr
<net::DrainableIOBuffer
> drainable
,
109 net::StreamSocket
* from
,
110 net::StreamSocket
* to
,
118 drainable
->DidConsume(result
);
119 if (drainable
->BytesRemaining() > 0) {
121 result
= to
->Write(drainable
.get(),
122 drainable
->BytesRemaining(),
123 base::Bind(&SocketPump::OnWritten
,
124 base::Unretained(this),
128 if (result
!= net::ERR_IO_PENDING
)
129 OnWritten(drainable
, from
, to
, result
);
133 if (pending_destruction_
) {
140 void SelfDestruct() {
141 if (pending_writes_
> 0) {
142 pending_destruction_
= true;
150 scoped_ptr
<net::StreamSocket
> client_socket_
;
151 scoped_ptr
<net::ServerSocket
> server_socket_
;
152 scoped_ptr
<net::StreamSocket
> accepted_socket_
;
154 bool pending_destruction_
;
159 typedef base::Callback
<void(uint16
, const std::string
&)> AcceptedCallback
;
161 BoundSocket(AcceptedCallback accepted_callback
,
162 const CreateServerSocketCallback
& socket_callback
)
163 : accepted_callback_(accepted_callback
),
164 socket_callback_(socket_callback
),
165 socket_(new net::TCPServerSocket(NULL
, net::NetLog::Source())),
169 virtual ~BoundSocket() {
172 bool Listen(uint16 port
) {
174 net::IPAddressNumber ip_number
;
175 if (!net::ParseIPLiteralToNumber(kLocalhost
, &ip_number
))
178 net::IPEndPoint
end_point(ip_number
, port
);
179 int result
= socket_
->Listen(end_point
, kListenBacklog
);
183 net::IPEndPoint local_address
;
184 result
= socket_
->GetLocalAddress(&local_address
);
193 typedef std::map
<net::IPEndPoint
, net::StreamSocket
*> AcceptedSocketsMap
;
197 int result
= socket_
->Accept(
199 base::Bind(&BoundSocket::OnAccepted
, base::Unretained(this)));
200 if (result
== net::ERR_IO_PENDING
)
203 HandleAcceptResult(result
);
207 void OnAccepted(int result
) {
208 HandleAcceptResult(result
);
209 if (result
== net::OK
)
213 void HandleAcceptResult(int result
) {
214 if (result
!= net::OK
)
217 SocketPump
* pump
= new SocketPump(accept_socket_
.release());
218 std::string name
= pump
->Init(socket_callback_
);
220 accepted_callback_
.Run(port_
, name
);
223 AcceptedCallback accepted_callback_
;
224 CreateServerSocketCallback socket_callback_
;
225 scoped_ptr
<net::ServerSocket
> socket_
;
226 scoped_ptr
<net::StreamSocket
> accept_socket_
;
232 // TetheringHandler::TetheringImpl -------------------------------------------
234 class TetheringHandler::TetheringImpl
{
237 base::WeakPtr
<TetheringHandler
> handler
,
238 const CreateServerSocketCallback
& socket_callback
);
241 void Bind(DevToolsCommandId command_id
, uint16 port
);
242 void Unbind(DevToolsCommandId command_id
, uint16 port
);
243 void Accepted(uint16 port
, const std::string
& name
);
246 void SendInternalError(DevToolsCommandId command_id
,
247 const std::string
& message
);
249 base::WeakPtr
<TetheringHandler
> handler_
;
250 CreateServerSocketCallback socket_callback_
;
252 typedef std::map
<uint16
, BoundSocket
*> BoundSockets
;
253 BoundSockets bound_sockets_
;
256 TetheringHandler::TetheringImpl::TetheringImpl(
257 base::WeakPtr
<TetheringHandler
> handler
,
258 const CreateServerSocketCallback
& socket_callback
)
260 socket_callback_(socket_callback
) {
263 TetheringHandler::TetheringImpl::~TetheringImpl() {
264 STLDeleteValues(&bound_sockets_
);
267 void TetheringHandler::TetheringImpl::Bind(
268 DevToolsCommandId command_id
, uint16 port
) {
269 if (bound_sockets_
.find(port
) != bound_sockets_
.end()) {
270 SendInternalError(command_id
, "Port already bound");
274 BoundSocket::AcceptedCallback callback
= base::Bind(
275 &TetheringHandler::TetheringImpl::Accepted
, base::Unretained(this));
276 scoped_ptr
<BoundSocket
> bound_socket(
277 new BoundSocket(callback
, socket_callback_
));
278 if (!bound_socket
->Listen(port
)) {
279 SendInternalError(command_id
, "Could not bind port");
283 bound_sockets_
[port
] = bound_socket
.release();
284 BrowserThread::PostTask(
287 base::Bind(&TetheringHandler::SendBindSuccess
, handler_
, command_id
));
290 void TetheringHandler::TetheringImpl::Unbind(
291 DevToolsCommandId command_id
, uint16 port
) {
293 BoundSockets::iterator it
= bound_sockets_
.find(port
);
294 if (it
== bound_sockets_
.end()) {
295 SendInternalError(command_id
, "Port is not bound");
300 bound_sockets_
.erase(it
);
301 BrowserThread::PostTask(
304 base::Bind(&TetheringHandler::SendUnbindSuccess
, handler_
, command_id
));
307 void TetheringHandler::TetheringImpl::Accepted(
308 uint16 port
, const std::string
& name
) {
309 BrowserThread::PostTask(
312 base::Bind(&TetheringHandler::Accepted
, handler_
, port
, name
));
315 void TetheringHandler::TetheringImpl::SendInternalError(
316 DevToolsCommandId command_id
,
317 const std::string
& message
) {
318 BrowserThread::PostTask(
321 base::Bind(&TetheringHandler::SendInternalError
, handler_
,
322 command_id
, message
));
326 // TetheringHandler ----------------------------------------------------------
329 TetheringHandler::TetheringImpl
* TetheringHandler::impl_
= nullptr;
331 TetheringHandler::TetheringHandler(
332 const CreateServerSocketCallback
& socket_callback
,
333 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
334 : socket_callback_(socket_callback
),
335 task_runner_(task_runner
),
337 weak_factory_(this) {
340 TetheringHandler::~TetheringHandler() {
342 task_runner_
->DeleteSoon(FROM_HERE
, impl_
);
347 void TetheringHandler::SetClient(scoped_ptr
<Client
> client
) {
348 client_
.swap(client
);
351 void TetheringHandler::Accepted(uint16 port
, const std::string
& name
) {
352 client_
->Accepted(AcceptedParams::Create()->set_port(port
)
353 ->set_connection_id(name
));
356 bool TetheringHandler::Activate() {
362 impl_
= new TetheringImpl(weak_factory_
.GetWeakPtr(), socket_callback_
);
366 Response
TetheringHandler::Bind(DevToolsCommandId command_id
, int port
) {
367 if (port
< kMinTetheringPort
|| port
> kMaxTetheringPort
)
368 return Response::InvalidParams("port");
371 return Response::ServerError("Tethering is used by another connection");
374 task_runner_
->PostTask(
375 FROM_HERE
, base::Bind(&TetheringImpl::Bind
, base::Unretained(impl_
),
377 return Response::OK();
380 Response
TetheringHandler::Unbind(DevToolsCommandId command_id
, int port
) {
382 return Response::ServerError("Tethering is used by another connection");
385 task_runner_
->PostTask(
386 FROM_HERE
, base::Bind(&TetheringImpl::Unbind
, base::Unretained(impl_
),
388 return Response::OK();
391 void TetheringHandler::SendBindSuccess(DevToolsCommandId command_id
) {
392 client_
->SendBindResponse(command_id
, BindResponse::Create());
395 void TetheringHandler::SendUnbindSuccess(DevToolsCommandId command_id
) {
396 client_
->SendUnbindResponse(command_id
, UnbindResponse::Create());
399 void TetheringHandler::SendInternalError(DevToolsCommandId command_id
,
400 const std::string
& message
) {
401 client_
->SendError(command_id
, Response::InternalError(message
));
404 } // namespace tethering
405 } // namespace devtools
406 } // namespace content