Change next_proto member type.
[chromium-blink-merge.git] / content / browser / devtools / protocol / tethering_handler.cc
blob0f00194a4d6da55e9ff9626eb9b0d7edfb398573
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 "content/public/browser/browser_thread.h"
8 #include "content/public/browser/devtools_http_handler_delegate.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"
15 namespace content {
16 namespace devtools {
17 namespace tethering {
19 namespace {
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;
31 class SocketPump {
32 public:
33 SocketPump(DevToolsHttpHandlerDelegate* delegate,
34 net::StreamSocket* client_socket)
35 : client_socket_(client_socket),
36 delegate_(delegate),
37 pending_writes_(0),
38 pending_destruction_(false) {
41 std::string Init() {
42 std::string channel_name;
43 server_socket_ = delegate_->CreateSocketForTethering(&channel_name);
44 if (!server_socket_.get() || channel_name.empty())
45 SelfDestruct();
47 int result = server_socket_->Accept(
48 &accepted_socket_,
49 base::Bind(&SocketPump::OnAccepted, base::Unretained(this)));
50 if (result != net::ERR_IO_PENDING)
51 OnAccepted(result);
52 return channel_name;
55 private:
56 void OnAccepted(int result) {
57 if (result < 0) {
58 SelfDestruct();
59 return;
62 ++pending_writes_; // avoid SelfDestruct in first Pump
63 Pump(client_socket_.get(), accepted_socket_.get());
64 --pending_writes_;
65 if (pending_destruction_) {
66 SelfDestruct();
67 } else {
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(
75 buffer.get(),
76 kBufferSize,
77 base::Bind(
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,
86 int result) {
87 if (result <= 0) {
88 SelfDestruct();
89 return;
92 int total = result;
93 scoped_refptr<net::DrainableIOBuffer> drainable =
94 new net::DrainableIOBuffer(buffer.get(), total);
96 ++pending_writes_;
97 result = to->Write(drainable.get(),
98 total,
99 base::Bind(&SocketPump::OnWritten,
100 base::Unretained(this),
101 drainable,
102 from,
103 to));
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,
111 int result) {
112 --pending_writes_;
113 if (result < 0) {
114 SelfDestruct();
115 return;
118 drainable->DidConsume(result);
119 if (drainable->BytesRemaining() > 0) {
120 ++pending_writes_;
121 result = to->Write(drainable.get(),
122 drainable->BytesRemaining(),
123 base::Bind(&SocketPump::OnWritten,
124 base::Unretained(this),
125 drainable,
126 from,
127 to));
128 if (result != net::ERR_IO_PENDING)
129 OnWritten(drainable, from, to, result);
130 return;
133 if (pending_destruction_) {
134 SelfDestruct();
135 return;
137 Pump(from, to);
140 void SelfDestruct() {
141 if (pending_writes_ > 0) {
142 pending_destruction_ = true;
143 return;
145 delete this;
149 private:
150 scoped_ptr<net::StreamSocket> client_socket_;
151 scoped_ptr<net::ServerSocket> server_socket_;
152 scoped_ptr<net::StreamSocket> accepted_socket_;
153 DevToolsHttpHandlerDelegate* delegate_;
154 int pending_writes_;
155 bool pending_destruction_;
158 class BoundSocket {
159 public:
160 typedef base::Callback<void(uint16, const std::string&)> AcceptedCallback;
162 BoundSocket(AcceptedCallback accepted_callback,
163 DevToolsHttpHandlerDelegate* delegate)
164 : accepted_callback_(accepted_callback),
165 delegate_(delegate),
166 socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
167 port_(0) {
170 virtual ~BoundSocket() {
173 bool Listen(uint16 port) {
174 port_ = port;
175 net::IPAddressNumber ip_number;
176 if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
177 return false;
179 net::IPEndPoint end_point(ip_number, port);
180 int result = socket_->Listen(end_point, kListenBacklog);
181 if (result < 0)
182 return false;
184 net::IPEndPoint local_address;
185 result = socket_->GetLocalAddress(&local_address);
186 if (result < 0)
187 return false;
189 DoAccept();
190 return true;
193 private:
194 typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
196 void DoAccept() {
197 while (true) {
198 int result = socket_->Accept(
199 &accept_socket_,
200 base::Bind(&BoundSocket::OnAccepted, base::Unretained(this)));
201 if (result == net::ERR_IO_PENDING)
202 break;
203 else
204 HandleAcceptResult(result);
208 void OnAccepted(int result) {
209 HandleAcceptResult(result);
210 if (result == net::OK)
211 DoAccept();
214 void HandleAcceptResult(int result) {
215 if (result != net::OK)
216 return;
218 SocketPump* pump = new SocketPump(delegate_, accept_socket_.release());
219 std::string name = pump->Init();
220 if (!name.empty())
221 accepted_callback_.Run(port_, name);
224 AcceptedCallback accepted_callback_;
225 DevToolsHttpHandlerDelegate* delegate_;
226 scoped_ptr<net::ServerSocket> socket_;
227 scoped_ptr<net::StreamSocket> accept_socket_;
228 uint16 port_;
231 } // namespace
233 // TetheringHandler::TetheringImpl -------------------------------------------
235 class TetheringHandler::TetheringImpl {
236 public:
237 TetheringImpl(
238 base::WeakPtr<TetheringHandler> handler,
239 DevToolsHttpHandlerDelegate* delegate);
240 ~TetheringImpl();
242 void Bind(DevToolsCommandId command_id, uint16 port);
243 void Unbind(DevToolsCommandId command_id, uint16 port);
244 void Accepted(uint16 port, const std::string& name);
246 private:
247 void SendInternalError(DevToolsCommandId command_id,
248 const std::string& message);
250 base::WeakPtr<TetheringHandler> handler_;
251 DevToolsHttpHandlerDelegate* delegate_;
253 typedef std::map<uint16, BoundSocket*> BoundSockets;
254 BoundSockets bound_sockets_;
257 TetheringHandler::TetheringImpl::TetheringImpl(
258 base::WeakPtr<TetheringHandler> handler,
259 DevToolsHttpHandlerDelegate* delegate)
260 : handler_(handler),
261 delegate_(delegate) {
264 TetheringHandler::TetheringImpl::~TetheringImpl() {
265 STLDeleteContainerPairSecondPointers(bound_sockets_.begin(),
266 bound_sockets_.end());
269 void TetheringHandler::TetheringImpl::Bind(
270 DevToolsCommandId command_id, uint16 port) {
271 if (bound_sockets_.find(port) != bound_sockets_.end()) {
272 SendInternalError(command_id, "Port already bound");
273 return;
276 BoundSocket::AcceptedCallback callback = base::Bind(
277 &TetheringHandler::TetheringImpl::Accepted, base::Unretained(this));
278 scoped_ptr<BoundSocket> bound_socket(new BoundSocket(callback, delegate_));
279 if (!bound_socket->Listen(port)) {
280 SendInternalError(command_id, "Could not bind port");
281 return;
284 bound_sockets_[port] = bound_socket.release();
285 BrowserThread::PostTask(
286 BrowserThread::UI,
287 FROM_HERE,
288 base::Bind(&TetheringHandler::SendBindSuccess, handler_, command_id));
291 void TetheringHandler::TetheringImpl::Unbind(
292 DevToolsCommandId command_id, uint16 port) {
294 BoundSockets::iterator it = bound_sockets_.find(port);
295 if (it == bound_sockets_.end()) {
296 SendInternalError(command_id, "Port is not bound");
297 return;
300 delete it->second;
301 bound_sockets_.erase(it);
302 BrowserThread::PostTask(
303 BrowserThread::UI,
304 FROM_HERE,
305 base::Bind(&TetheringHandler::SendUnbindSuccess, handler_, command_id));
308 void TetheringHandler::TetheringImpl::Accepted(
309 uint16 port, const std::string& name) {
310 BrowserThread::PostTask(
311 BrowserThread::UI,
312 FROM_HERE,
313 base::Bind(&TetheringHandler::Accepted, handler_, port, name));
316 void TetheringHandler::TetheringImpl::SendInternalError(
317 DevToolsCommandId command_id,
318 const std::string& message) {
319 BrowserThread::PostTask(
320 BrowserThread::UI,
321 FROM_HERE,
322 base::Bind(&TetheringHandler::SendInternalError, handler_,
323 command_id, message));
327 // TetheringHandler ----------------------------------------------------------
329 // static
330 TetheringHandler::TetheringImpl* TetheringHandler::impl_ = nullptr;
332 TetheringHandler::TetheringHandler(
333 DevToolsHttpHandlerDelegate* delegate,
334 scoped_refptr<base::MessageLoopProxy> message_loop_proxy)
335 : delegate_(delegate),
336 message_loop_proxy_(message_loop_proxy),
337 is_active_(false),
338 weak_factory_(this) {
341 TetheringHandler::~TetheringHandler() {
342 if (is_active_) {
343 message_loop_proxy_->DeleteSoon(FROM_HERE, impl_);
344 impl_ = nullptr;
348 void TetheringHandler::SetClient(scoped_ptr<Client> client) {
349 client_.swap(client);
352 void TetheringHandler::Accepted(uint16 port, const std::string& name) {
353 client_->Accepted(AcceptedParams::Create()->set_port(port)
354 ->set_connection_id(name));
357 bool TetheringHandler::Activate() {
358 if (is_active_)
359 return true;
360 if (impl_)
361 return false;
362 is_active_ = true;
363 impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), delegate_);
364 return true;
367 Response TetheringHandler::Bind(DevToolsCommandId command_id, int port) {
368 if (port < kMinTetheringPort || port > kMaxTetheringPort)
369 return Response::InvalidParams("port");
371 if (!Activate())
372 return Response::ServerError("Tethering is used by another connection");
374 DCHECK(impl_);
375 message_loop_proxy_->PostTask(
376 FROM_HERE,
377 base::Bind(&TetheringImpl::Bind, base::Unretained(impl_),
378 command_id, port));
379 return Response::OK();
382 Response TetheringHandler::Unbind(DevToolsCommandId command_id, int port) {
383 if (!Activate())
384 return Response::ServerError("Tethering is used by another connection");
386 DCHECK(impl_);
387 message_loop_proxy_->PostTask(
388 FROM_HERE,
389 base::Bind(&TetheringImpl::Unbind, base::Unretained(impl_),
390 command_id, port));
391 return Response::OK();
394 void TetheringHandler::SendBindSuccess(DevToolsCommandId command_id) {
395 client_->SendBindResponse(command_id, BindResponse::Create());
398 void TetheringHandler::SendUnbindSuccess(DevToolsCommandId command_id) {
399 client_->SendUnbindResponse(command_id, UnbindResponse::Create());
402 void TetheringHandler::SendInternalError(DevToolsCommandId command_id,
403 const std::string& message) {
404 client_->SendError(command_id, Response::InternalError(message));
407 } // namespace tethering
408 } // namespace devtools
409 } // namespace content