Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: content/browser/devtools/tethering_handler.cc

Issue 658163003: [DevTools] Added browser protocol to handler generator (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@singleUse
Patch Set: GN fix Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/browser/devtools/tethering_handler.h ('k') | content/content_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "content/browser/devtools/tethering_handler.h"
6
7 #include "base/bind.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"
22
23 namespace content {
24
25 namespace {
26
27 const char kLocalhost[] = "127.0.0.1";
28
29 const int kListenBacklog = 5;
30 const int kBufferSize = 16 * 1024;
31
32 const int kMinTetheringPort = 1024;
33 const int kMaxTetheringPort = 32767;
34
35 class SocketPump {
36 public:
37 SocketPump(DevToolsHttpHandlerDelegate* delegate,
38 net::StreamSocket* client_socket)
39 : client_socket_(client_socket),
40 delegate_(delegate),
41 pending_writes_(0),
42 pending_destruction_(false) {
43 }
44
45 std::string Init() {
46 std::string channel_name;
47 server_socket_ = delegate_->CreateSocketForTethering(&channel_name);
48 if (!server_socket_.get() || channel_name.empty())
49 SelfDestruct();
50
51 int result = server_socket_->Accept(
52 &accepted_socket_,
53 base::Bind(&SocketPump::OnAccepted, base::Unretained(this)));
54 if (result != net::ERR_IO_PENDING)
55 OnAccepted(result);
56 return channel_name;
57 }
58
59 private:
60 void OnAccepted(int result) {
61 if (result < 0) {
62 SelfDestruct();
63 return;
64 }
65
66 ++pending_writes_; // avoid SelfDestruct in first Pump
67 Pump(client_socket_.get(), accepted_socket_.get());
68 --pending_writes_;
69 if (pending_destruction_) {
70 SelfDestruct();
71 } else {
72 Pump(accepted_socket_.get(), client_socket_.get());
73 }
74 }
75
76 void Pump(net::StreamSocket* from, net::StreamSocket* to) {
77 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize);
78 int result = from->Read(
79 buffer.get(),
80 kBufferSize,
81 base::Bind(
82 &SocketPump::OnRead, base::Unretained(this), from, to, buffer));
83 if (result != net::ERR_IO_PENDING)
84 OnRead(from, to, buffer, result);
85 }
86
87 void OnRead(net::StreamSocket* from,
88 net::StreamSocket* to,
89 scoped_refptr<net::IOBuffer> buffer,
90 int result) {
91 if (result <= 0) {
92 SelfDestruct();
93 return;
94 }
95
96 int total = result;
97 scoped_refptr<net::DrainableIOBuffer> drainable =
98 new net::DrainableIOBuffer(buffer.get(), total);
99
100 ++pending_writes_;
101 result = to->Write(drainable.get(),
102 total,
103 base::Bind(&SocketPump::OnWritten,
104 base::Unretained(this),
105 drainable,
106 from,
107 to));
108 if (result != net::ERR_IO_PENDING)
109 OnWritten(drainable, from, to, result);
110 }
111
112 void OnWritten(scoped_refptr<net::DrainableIOBuffer> drainable,
113 net::StreamSocket* from,
114 net::StreamSocket* to,
115 int result) {
116 --pending_writes_;
117 if (result < 0) {
118 SelfDestruct();
119 return;
120 }
121
122 drainable->DidConsume(result);
123 if (drainable->BytesRemaining() > 0) {
124 ++pending_writes_;
125 result = to->Write(drainable.get(),
126 drainable->BytesRemaining(),
127 base::Bind(&SocketPump::OnWritten,
128 base::Unretained(this),
129 drainable,
130 from,
131 to));
132 if (result != net::ERR_IO_PENDING)
133 OnWritten(drainable, from, to, result);
134 return;
135 }
136
137 if (pending_destruction_) {
138 SelfDestruct();
139 return;
140 }
141 Pump(from, to);
142 }
143
144 void SelfDestruct() {
145 if (pending_writes_ > 0) {
146 pending_destruction_ = true;
147 return;
148 }
149 delete this;
150 }
151
152
153 private:
154 scoped_ptr<net::StreamSocket> client_socket_;
155 scoped_ptr<net::ServerSocket> server_socket_;
156 scoped_ptr<net::StreamSocket> accepted_socket_;
157 DevToolsHttpHandlerDelegate* delegate_;
158 int pending_writes_;
159 bool pending_destruction_;
160 };
161
162 static int GetPort(scoped_refptr<DevToolsProtocol::Command> command,
163 const std::string& paramName) {
164 base::DictionaryValue* params = command->params();
165 int port = 0;
166 if (!params ||
167 !params->GetInteger(paramName, &port) ||
168 port < kMinTetheringPort || port > kMaxTetheringPort)
169 return 0;
170 return port;
171 }
172
173 class BoundSocket {
174 public:
175 typedef base::Callback<void(int, const std::string&)> AcceptedCallback;
176
177 BoundSocket(AcceptedCallback accepted_callback,
178 DevToolsHttpHandlerDelegate* delegate)
179 : accepted_callback_(accepted_callback),
180 delegate_(delegate),
181 socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
182 port_(0) {
183 }
184
185 virtual ~BoundSocket() {
186 }
187
188 bool Listen(int port) {
189 port_ = port;
190 net::IPAddressNumber ip_number;
191 if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
192 return false;
193
194 net::IPEndPoint end_point(ip_number, port);
195 int result = socket_->Listen(end_point, kListenBacklog);
196 if (result < 0)
197 return false;
198
199 net::IPEndPoint local_address;
200 result = socket_->GetLocalAddress(&local_address);
201 if (result < 0)
202 return false;
203
204 DoAccept();
205 return true;
206 }
207
208 private:
209 typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
210
211 void DoAccept() {
212 while (true) {
213 int result = socket_->Accept(
214 &accept_socket_,
215 base::Bind(&BoundSocket::OnAccepted, base::Unretained(this)));
216 if (result == net::ERR_IO_PENDING)
217 break;
218 else
219 HandleAcceptResult(result);
220 }
221 }
222
223 void OnAccepted(int result) {
224 HandleAcceptResult(result);
225 if (result == net::OK)
226 DoAccept();
227 }
228
229 void HandleAcceptResult(int result) {
230 if (result != net::OK)
231 return;
232
233 SocketPump* pump = new SocketPump(delegate_, accept_socket_.release());
234 std::string name = pump->Init();
235 if (!name.empty())
236 accepted_callback_.Run(port_, name);
237 }
238
239 AcceptedCallback accepted_callback_;
240 DevToolsHttpHandlerDelegate* delegate_;
241 scoped_ptr<net::ServerSocket> socket_;
242 scoped_ptr<net::StreamSocket> accept_socket_;
243 int port_;
244 };
245
246 } // namespace
247
248 // TetheringHandler::TetheringImpl -------------------------------------------
249
250 class TetheringHandler::TetheringImpl {
251 public:
252 TetheringImpl(
253 base::WeakPtr<TetheringHandler> handler,
254 DevToolsHttpHandlerDelegate* delegate);
255 ~TetheringImpl();
256
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);
260
261 private:
262 void SendInternalError(scoped_refptr<DevToolsProtocol::Command> command,
263 const std::string& message);
264
265 base::WeakPtr<TetheringHandler> handler_;
266 DevToolsHttpHandlerDelegate* delegate_;
267
268 typedef std::map<int, BoundSocket*> BoundSockets;
269 BoundSockets bound_sockets_;
270 };
271
272 TetheringHandler::TetheringImpl::TetheringImpl(
273 base::WeakPtr<TetheringHandler> handler,
274 DevToolsHttpHandlerDelegate* delegate)
275 : handler_(handler),
276 delegate_(delegate) {
277 }
278
279 TetheringHandler::TetheringImpl::~TetheringImpl() {
280 STLDeleteContainerPairSecondPointers(bound_sockets_.begin(),
281 bound_sockets_.end());
282 }
283
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");
288 return;
289 }
290
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");
296 return;
297 }
298
299 bound_sockets_[port] = bound_socket.release();
300 BrowserThread::PostTask(
301 BrowserThread::UI,
302 FROM_HERE,
303 base::Bind(&TetheringHandler::SendBindSuccess, handler_, command));
304 }
305
306 void TetheringHandler::TetheringImpl::Unbind(
307 scoped_refptr<DevToolsProtocol::Command> command, int port) {
308
309 BoundSockets::iterator it = bound_sockets_.find(port);
310 if (it == bound_sockets_.end()) {
311 SendInternalError(command, "Port is not bound");
312 return;
313 }
314
315 delete it->second;
316 bound_sockets_.erase(it);
317 BrowserThread::PostTask(
318 BrowserThread::UI,
319 FROM_HERE,
320 base::Bind(&TetheringHandler::SendUnbindSuccess, handler_, command));
321 }
322
323 void TetheringHandler::TetheringImpl::Accepted(
324 int port, const std::string& name) {
325 BrowserThread::PostTask(
326 BrowserThread::UI,
327 FROM_HERE,
328 base::Bind(&TetheringHandler::Accepted, handler_, port, name));
329 }
330
331 void TetheringHandler::TetheringImpl::SendInternalError(
332 scoped_refptr<DevToolsProtocol::Command> command,
333 const std::string& message) {
334 BrowserThread::PostTask(
335 BrowserThread::UI,
336 FROM_HERE,
337 base::Bind(&TetheringHandler::SendInternalError, handler_,
338 command, message));
339 }
340
341
342 // TetheringHandler ----------------------------------------------------------
343
344 // static
345 TetheringHandler::TetheringImpl* TetheringHandler::impl_ = nullptr;
346
347 TetheringHandler::TetheringHandler(
348 DevToolsHttpHandlerDelegate* delegate,
349 scoped_refptr<base::MessageLoopProxy> message_loop_proxy)
350 : delegate_(delegate),
351 message_loop_proxy_(message_loop_proxy),
352 is_active_(false),
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)));
360 }
361
362 TetheringHandler::~TetheringHandler() {
363 if (is_active_) {
364 message_loop_proxy_->DeleteSoon(FROM_HERE, impl_);
365 impl_ = nullptr;
366 }
367 }
368
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);
374 }
375
376 bool TetheringHandler::Activate() {
377 if (is_active_)
378 return true;
379 if (impl_)
380 return false;
381 is_active_ = true;
382 impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), delegate_);
383 return true;
384 }
385
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);
390 if (port == 0)
391 return command->InvalidParamResponse(portParamName);
392
393 if (!Activate()) {
394 return command->ServerErrorResponse(
395 "Tethering is used by another connection");
396 }
397 DCHECK(impl_);
398 message_loop_proxy_->PostTask(
399 FROM_HERE,
400 base::Bind(&TetheringImpl::Bind, base::Unretained(impl_),
401 command, port));
402 return command->AsyncResponsePromise();
403 }
404
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);
409 if (port == 0)
410 return command->InvalidParamResponse(portParamName);
411
412 if (!Activate()) {
413 return command->ServerErrorResponse(
414 "Tethering is used by another connection");
415 }
416 DCHECK(impl_);
417 message_loop_proxy_->PostTask(
418 FROM_HERE,
419 base::Bind(&TetheringImpl::Unbind, base::Unretained(impl_),
420 command, port));
421 return command->AsyncResponsePromise();
422 }
423
424 void TetheringHandler::SendBindSuccess(
425 scoped_refptr<DevToolsProtocol::Command> command) {
426 SendAsyncResponse(command->SuccessResponse(nullptr));
427 }
428
429 void TetheringHandler::SendUnbindSuccess(
430 scoped_refptr<DevToolsProtocol::Command> command) {
431 SendAsyncResponse(command->SuccessResponse(nullptr));
432 }
433
434 void TetheringHandler::SendInternalError(
435 scoped_refptr<DevToolsProtocol::Command> command,
436 const std::string& message) {
437 SendAsyncResponse(command->InternalErrorResponse(message));
438 }
439
440 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/devtools/tethering_handler.h ('k') | content/content_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698