| OLD | NEW |
| (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 | |
| OLD | NEW |