[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / devtools / protocol / tethering_handler.cc
blob9b964f49d3827def0c320424d60f6cd74f7a6501
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"
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;
30 using CreateServerSocketCallback =
31 base::Callback<scoped_ptr<net::ServerSocket>(std::string*)>;
33 class SocketPump {
34 public:
35 SocketPump(net::StreamSocket* client_socket)
36 : client_socket_(client_socket),
37 pending_writes_(0),
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())
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 int pending_writes_;
154 bool pending_destruction_;
157 class BoundSocket {
158 public:
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())),
166 port_(0) {
169 virtual ~BoundSocket() {
172 bool Listen(uint16 port) {
173 port_ = port;
174 net::IPAddressNumber ip_number;
175 if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
176 return false;
178 net::IPEndPoint end_point(ip_number, port);
179 int result = socket_->Listen(end_point, kListenBacklog);
180 if (result < 0)
181 return false;
183 net::IPEndPoint local_address;
184 result = socket_->GetLocalAddress(&local_address);
185 if (result < 0)
186 return false;
188 DoAccept();
189 return true;
192 private:
193 typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
195 void DoAccept() {
196 while (true) {
197 int result = socket_->Accept(
198 &accept_socket_,
199 base::Bind(&BoundSocket::OnAccepted, base::Unretained(this)));
200 if (result == net::ERR_IO_PENDING)
201 break;
202 else
203 HandleAcceptResult(result);
207 void OnAccepted(int result) {
208 HandleAcceptResult(result);
209 if (result == net::OK)
210 DoAccept();
213 void HandleAcceptResult(int result) {
214 if (result != net::OK)
215 return;
217 SocketPump* pump = new SocketPump(accept_socket_.release());
218 std::string name = pump->Init(socket_callback_);
219 if (!name.empty())
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_;
227 uint16 port_;
230 } // namespace
232 // TetheringHandler::TetheringImpl -------------------------------------------
234 class TetheringHandler::TetheringImpl {
235 public:
236 TetheringImpl(
237 base::WeakPtr<TetheringHandler> handler,
238 const CreateServerSocketCallback& socket_callback);
239 ~TetheringImpl();
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);
245 private:
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)
259 : handler_(handler),
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");
271 return;
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");
280 return;
283 bound_sockets_[port] = bound_socket.release();
284 BrowserThread::PostTask(
285 BrowserThread::UI,
286 FROM_HERE,
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");
296 return;
299 delete it->second;
300 bound_sockets_.erase(it);
301 BrowserThread::PostTask(
302 BrowserThread::UI,
303 FROM_HERE,
304 base::Bind(&TetheringHandler::SendUnbindSuccess, handler_, command_id));
307 void TetheringHandler::TetheringImpl::Accepted(
308 uint16 port, const std::string& name) {
309 BrowserThread::PostTask(
310 BrowserThread::UI,
311 FROM_HERE,
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(
319 BrowserThread::UI,
320 FROM_HERE,
321 base::Bind(&TetheringHandler::SendInternalError, handler_,
322 command_id, message));
326 // TetheringHandler ----------------------------------------------------------
328 // static
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),
336 is_active_(false),
337 weak_factory_(this) {
340 TetheringHandler::~TetheringHandler() {
341 if (is_active_) {
342 task_runner_->DeleteSoon(FROM_HERE, impl_);
343 impl_ = nullptr;
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() {
357 if (is_active_)
358 return true;
359 if (impl_)
360 return false;
361 is_active_ = true;
362 impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), socket_callback_);
363 return true;
366 Response TetheringHandler::Bind(DevToolsCommandId command_id, int port) {
367 if (port < kMinTetheringPort || port > kMaxTetheringPort)
368 return Response::InvalidParams("port");
370 if (!Activate())
371 return Response::ServerError("Tethering is used by another connection");
373 DCHECK(impl_);
374 task_runner_->PostTask(
375 FROM_HERE, base::Bind(&TetheringImpl::Bind, base::Unretained(impl_),
376 command_id, port));
377 return Response::OK();
380 Response TetheringHandler::Unbind(DevToolsCommandId command_id, int port) {
381 if (!Activate())
382 return Response::ServerError("Tethering is used by another connection");
384 DCHECK(impl_);
385 task_runner_->PostTask(
386 FROM_HERE, base::Bind(&TetheringImpl::Unbind, base::Unretained(impl_),
387 command_id, port));
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