| 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/stream_listen_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 : public net::StreamListenSocket::Delegate { | |
| 36 public: | |
| 37 SocketPump(DevToolsHttpHandlerDelegate* delegate, | |
| 38 net::StreamSocket* client_socket) | |
| 39 : client_socket_(client_socket), | |
| 40 delegate_(delegate), | |
| 41 wire_buffer_size_(0), | |
| 42 pending_destruction_(false) { | |
| 43 } | |
| 44 | |
| 45 std::string Init() { | |
| 46 std::string channel_name; | |
| 47 server_socket_ = delegate_->CreateSocketForTethering(this, &channel_name); | |
| 48 if (!server_socket_.get() || channel_name.empty()) | |
| 49 SelfDestruct(); | |
| 50 return channel_name; | |
| 51 } | |
| 52 | |
| 53 ~SocketPump() override {} | |
| 54 | |
| 55 private: | |
| 56 void DidAccept(net::StreamListenSocket* server, | |
| 57 scoped_ptr<net::StreamListenSocket> socket) override { | |
| 58 if (accepted_socket_.get()) | |
| 59 return; | |
| 60 | |
| 61 buffer_ = new net::IOBuffer(kBufferSize); | |
| 62 wire_buffer_ = new net::GrowableIOBuffer(); | |
| 63 wire_buffer_->SetCapacity(kBufferSize); | |
| 64 | |
| 65 accepted_socket_ = socket.Pass(); | |
| 66 int result = client_socket_->Read( | |
| 67 buffer_.get(), | |
| 68 kBufferSize, | |
| 69 base::Bind(&SocketPump::OnClientRead, base::Unretained(this))); | |
| 70 if (result != net::ERR_IO_PENDING) | |
| 71 OnClientRead(result); | |
| 72 } | |
| 73 | |
| 74 void DidRead(net::StreamListenSocket* socket, | |
| 75 const char* data, | |
| 76 int len) override { | |
| 77 int old_size = wire_buffer_size_; | |
| 78 wire_buffer_size_ += len; | |
| 79 while (wire_buffer_->capacity() < wire_buffer_size_) | |
| 80 wire_buffer_->SetCapacity(wire_buffer_->capacity() * 2); | |
| 81 memcpy(wire_buffer_->StartOfBuffer() + old_size, data, len); | |
| 82 if (old_size != wire_buffer_->offset()) | |
| 83 return; | |
| 84 OnClientWrite(0); | |
| 85 } | |
| 86 | |
| 87 void DidClose(net::StreamListenSocket* socket) override { SelfDestruct(); } | |
| 88 | |
| 89 void OnClientRead(int result) { | |
| 90 if (result <= 0) { | |
| 91 SelfDestruct(); | |
| 92 return; | |
| 93 } | |
| 94 | |
| 95 accepted_socket_->Send(buffer_->data(), result); | |
| 96 result = client_socket_->Read( | |
| 97 buffer_.get(), | |
| 98 kBufferSize, | |
| 99 base::Bind(&SocketPump::OnClientRead, base::Unretained(this))); | |
| 100 if (result != net::ERR_IO_PENDING) | |
| 101 OnClientRead(result); | |
| 102 } | |
| 103 | |
| 104 void OnClientWrite(int result) { | |
| 105 if (result < 0) { | |
| 106 SelfDestruct(); | |
| 107 return; | |
| 108 } | |
| 109 | |
| 110 wire_buffer_->set_offset(wire_buffer_->offset() + result); | |
| 111 | |
| 112 int remaining = wire_buffer_size_ - wire_buffer_->offset(); | |
| 113 if (remaining == 0) { | |
| 114 if (pending_destruction_) | |
| 115 SelfDestruct(); | |
| 116 return; | |
| 117 } | |
| 118 | |
| 119 | |
| 120 if (remaining > kBufferSize) | |
| 121 remaining = kBufferSize; | |
| 122 | |
| 123 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(remaining); | |
| 124 memcpy(buffer->data(), wire_buffer_->data(), remaining); | |
| 125 result = client_socket_->Write( | |
| 126 buffer.get(), | |
| 127 remaining, | |
| 128 base::Bind(&SocketPump::OnClientWrite, base::Unretained(this))); | |
| 129 | |
| 130 // Shrink buffer | |
| 131 int offset = wire_buffer_->offset(); | |
| 132 if (offset > kBufferSize) { | |
| 133 memcpy(wire_buffer_->StartOfBuffer(), wire_buffer_->data(), | |
| 134 wire_buffer_size_ - offset); | |
| 135 wire_buffer_size_ -= offset; | |
| 136 wire_buffer_->set_offset(0); | |
| 137 } | |
| 138 | |
| 139 if (result != net::ERR_IO_PENDING) | |
| 140 OnClientWrite(result); | |
| 141 return; | |
| 142 } | |
| 143 | |
| 144 void SelfDestruct() { | |
| 145 if (wire_buffer_.get() && wire_buffer_->offset() != wire_buffer_size_) { | |
| 146 pending_destruction_ = true; | |
| 147 return; | |
| 148 } | |
| 149 delete this; | |
| 150 } | |
| 151 | |
| 152 private: | |
| 153 scoped_ptr<net::StreamSocket> client_socket_; | |
| 154 scoped_ptr<net::StreamListenSocket> server_socket_; | |
| 155 scoped_ptr<net::StreamListenSocket> accepted_socket_; | |
| 156 scoped_refptr<net::IOBuffer> buffer_; | |
| 157 scoped_refptr<net::GrowableIOBuffer> wire_buffer_; | |
| 158 DevToolsHttpHandlerDelegate* delegate_; | |
| 159 int wire_buffer_size_; | |
| 160 bool pending_destruction_; | |
| 161 }; | |
| 162 | |
| 163 static int GetPort(scoped_refptr<DevToolsProtocol::Command> command, | |
| 164 const std::string& paramName) { | |
| 165 base::DictionaryValue* params = command->params(); | |
| 166 int port = 0; | |
| 167 if (!params || | |
| 168 !params->GetInteger(paramName, &port) || | |
| 169 port < kMinTetheringPort || port > kMaxTetheringPort) | |
| 170 return 0; | |
| 171 return port; | |
| 172 } | |
| 173 | |
| 174 class BoundSocket { | |
| 175 public: | |
| 176 typedef base::Callback<void(int, const std::string&)> AcceptedCallback; | |
| 177 | |
| 178 BoundSocket(AcceptedCallback accepted_callback, | |
| 179 DevToolsHttpHandlerDelegate* delegate) | |
| 180 : accepted_callback_(accepted_callback), | |
| 181 delegate_(delegate), | |
| 182 socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())), | |
| 183 port_(0) { | |
| 184 } | |
| 185 | |
| 186 virtual ~BoundSocket() { | |
| 187 } | |
| 188 | |
| 189 bool Listen(int port) { | |
| 190 port_ = port; | |
| 191 net::IPAddressNumber ip_number; | |
| 192 if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number)) | |
| 193 return false; | |
| 194 | |
| 195 net::IPEndPoint end_point(ip_number, port); | |
| 196 int result = socket_->Listen(end_point, kListenBacklog); | |
| 197 if (result < 0) | |
| 198 return false; | |
| 199 | |
| 200 net::IPEndPoint local_address; | |
| 201 result = socket_->GetLocalAddress(&local_address); | |
| 202 if (result < 0) | |
| 203 return false; | |
| 204 | |
| 205 DoAccept(); | |
| 206 return true; | |
| 207 } | |
| 208 | |
| 209 private: | |
| 210 typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap; | |
| 211 | |
| 212 void DoAccept() { | |
| 213 while (true) { | |
| 214 int result = socket_->Accept( | |
| 215 &accept_socket_, | |
| 216 base::Bind(&BoundSocket::OnAccepted, base::Unretained(this))); | |
| 217 if (result == net::ERR_IO_PENDING) | |
| 218 break; | |
| 219 else | |
| 220 HandleAcceptResult(result); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 void OnAccepted(int result) { | |
| 225 HandleAcceptResult(result); | |
| 226 if (result == net::OK) | |
| 227 DoAccept(); | |
| 228 } | |
| 229 | |
| 230 void HandleAcceptResult(int result) { | |
| 231 if (result != net::OK) | |
| 232 return; | |
| 233 | |
| 234 SocketPump* pump = new SocketPump(delegate_, accept_socket_.release()); | |
| 235 std::string name = pump->Init(); | |
| 236 if (!name.empty()) | |
| 237 accepted_callback_.Run(port_, name); | |
| 238 } | |
| 239 | |
| 240 AcceptedCallback accepted_callback_; | |
| 241 DevToolsHttpHandlerDelegate* delegate_; | |
| 242 scoped_ptr<net::ServerSocket> socket_; | |
| 243 scoped_ptr<net::StreamSocket> accept_socket_; | |
| 244 int port_; | |
| 245 }; | |
| 246 | |
| 247 } // namespace | |
| 248 | |
| 249 // TetheringHandler::TetheringImpl ------------------------------------------- | |
| 250 | |
| 251 class TetheringHandler::TetheringImpl { | |
| 252 public: | |
| 253 TetheringImpl( | |
| 254 base::WeakPtr<TetheringHandler> handler, | |
| 255 DevToolsHttpHandlerDelegate* delegate); | |
| 256 ~TetheringImpl(); | |
| 257 | |
| 258 void Bind(scoped_refptr<DevToolsProtocol::Command> command, int port); | |
| 259 void Unbind(scoped_refptr<DevToolsProtocol::Command> command, int port); | |
| 260 void Accepted(int port, const std::string& name); | |
| 261 | |
| 262 private: | |
| 263 void SendInternalError(scoped_refptr<DevToolsProtocol::Command> command, | |
| 264 const std::string& message); | |
| 265 | |
| 266 base::WeakPtr<TetheringHandler> handler_; | |
| 267 DevToolsHttpHandlerDelegate* delegate_; | |
| 268 | |
| 269 typedef std::map<int, BoundSocket*> BoundSockets; | |
| 270 BoundSockets bound_sockets_; | |
| 271 }; | |
| 272 | |
| 273 TetheringHandler::TetheringImpl::TetheringImpl( | |
| 274 base::WeakPtr<TetheringHandler> handler, | |
| 275 DevToolsHttpHandlerDelegate* delegate) | |
| 276 : handler_(handler), | |
| 277 delegate_(delegate) { | |
| 278 } | |
| 279 | |
| 280 TetheringHandler::TetheringImpl::~TetheringImpl() { | |
| 281 STLDeleteContainerPairSecondPointers(bound_sockets_.begin(), | |
| 282 bound_sockets_.end()); | |
| 283 } | |
| 284 | |
| 285 void TetheringHandler::TetheringImpl::Bind( | |
| 286 scoped_refptr<DevToolsProtocol::Command> command, int port) { | |
| 287 if (bound_sockets_.find(port) != bound_sockets_.end()) { | |
| 288 SendInternalError(command, "Port already bound"); | |
| 289 return; | |
| 290 } | |
| 291 | |
| 292 BoundSocket::AcceptedCallback callback = base::Bind( | |
| 293 &TetheringHandler::TetheringImpl::Accepted, base::Unretained(this)); | |
| 294 scoped_ptr<BoundSocket> bound_socket(new BoundSocket(callback, delegate_)); | |
| 295 if (!bound_socket->Listen(port)) { | |
| 296 SendInternalError(command, "Could not bind port"); | |
| 297 return; | |
| 298 } | |
| 299 | |
| 300 bound_sockets_[port] = bound_socket.release(); | |
| 301 BrowserThread::PostTask( | |
| 302 BrowserThread::UI, | |
| 303 FROM_HERE, | |
| 304 base::Bind(&TetheringHandler::SendBindSuccess, handler_, command)); | |
| 305 } | |
| 306 | |
| 307 void TetheringHandler::TetheringImpl::Unbind( | |
| 308 scoped_refptr<DevToolsProtocol::Command> command, int port) { | |
| 309 | |
| 310 BoundSockets::iterator it = bound_sockets_.find(port); | |
| 311 if (it == bound_sockets_.end()) { | |
| 312 SendInternalError(command, "Port is not bound"); | |
| 313 return; | |
| 314 } | |
| 315 | |
| 316 delete it->second; | |
| 317 bound_sockets_.erase(it); | |
| 318 BrowserThread::PostTask( | |
| 319 BrowserThread::UI, | |
| 320 FROM_HERE, | |
| 321 base::Bind(&TetheringHandler::SendUnbindSuccess, handler_, command)); | |
| 322 } | |
| 323 | |
| 324 void TetheringHandler::TetheringImpl::Accepted( | |
| 325 int port, const std::string& name) { | |
| 326 BrowserThread::PostTask( | |
| 327 BrowserThread::UI, | |
| 328 FROM_HERE, | |
| 329 base::Bind(&TetheringHandler::Accepted, handler_, port, name)); | |
| 330 } | |
| 331 | |
| 332 void TetheringHandler::TetheringImpl::SendInternalError( | |
| 333 scoped_refptr<DevToolsProtocol::Command> command, | |
| 334 const std::string& message) { | |
| 335 BrowserThread::PostTask( | |
| 336 BrowserThread::UI, | |
| 337 FROM_HERE, | |
| 338 base::Bind(&TetheringHandler::SendInternalError, handler_, | |
| 339 command, message)); | |
| 340 } | |
| 341 | |
| 342 | |
| 343 // TetheringHandler ---------------------------------------------------------- | |
| 344 | |
| 345 // static | |
| 346 TetheringHandler::TetheringImpl* TetheringHandler::impl_ = nullptr; | |
| 347 | |
| 348 TetheringHandler::TetheringHandler( | |
| 349 DevToolsHttpHandlerDelegate* delegate, | |
| 350 scoped_refptr<base::MessageLoopProxy> message_loop_proxy) | |
| 351 : delegate_(delegate), | |
| 352 message_loop_proxy_(message_loop_proxy), | |
| 353 is_active_(false), | |
| 354 weak_factory_(this) { | |
| 355 RegisterCommandHandler(devtools::Tethering::bind::kName, | |
| 356 base::Bind(&TetheringHandler::OnBind, | |
| 357 base::Unretained(this))); | |
| 358 RegisterCommandHandler(devtools::Tethering::unbind::kName, | |
| 359 base::Bind(&TetheringHandler::OnUnbind, | |
| 360 base::Unretained(this))); | |
| 361 } | |
| 362 | |
| 363 TetheringHandler::~TetheringHandler() { | |
| 364 if (is_active_) { | |
| 365 message_loop_proxy_->DeleteSoon(FROM_HERE, impl_); | |
| 366 impl_ = nullptr; | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 void TetheringHandler::Accepted(int port, const std::string& name) { | |
| 371 base::DictionaryValue* params = new base::DictionaryValue(); | |
| 372 params->SetInteger(devtools::Tethering::accepted::kParamPort, port); | |
| 373 params->SetString(devtools::Tethering::accepted::kParamConnectionId, name); | |
| 374 SendNotification(devtools::Tethering::accepted::kName, params); | |
| 375 } | |
| 376 | |
| 377 bool TetheringHandler::Activate() { | |
| 378 if (is_active_) | |
| 379 return true; | |
| 380 if (impl_) | |
| 381 return false; | |
| 382 is_active_ = true; | |
| 383 impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), delegate_); | |
| 384 return true; | |
| 385 } | |
| 386 | |
| 387 scoped_refptr<DevToolsProtocol::Response> | |
| 388 TetheringHandler::OnBind(scoped_refptr<DevToolsProtocol::Command> command) { | |
| 389 const std::string& portParamName = devtools::Tethering::bind::kParamPort; | |
| 390 int port = GetPort(command, portParamName); | |
| 391 if (port == 0) | |
| 392 return command->InvalidParamResponse(portParamName); | |
| 393 | |
| 394 if (!Activate()) { | |
| 395 return command->ServerErrorResponse( | |
| 396 "Tethering is used by another connection"); | |
| 397 } | |
| 398 DCHECK(impl_); | |
| 399 message_loop_proxy_->PostTask( | |
| 400 FROM_HERE, | |
| 401 base::Bind(&TetheringImpl::Bind, base::Unretained(impl_), | |
| 402 command, port)); | |
| 403 return command->AsyncResponsePromise(); | |
| 404 } | |
| 405 | |
| 406 scoped_refptr<DevToolsProtocol::Response> | |
| 407 TetheringHandler::OnUnbind(scoped_refptr<DevToolsProtocol::Command> command) { | |
| 408 const std::string& portParamName = devtools::Tethering::unbind::kParamPort; | |
| 409 int port = GetPort(command, portParamName); | |
| 410 if (port == 0) | |
| 411 return command->InvalidParamResponse(portParamName); | |
| 412 | |
| 413 if (!Activate()) { | |
| 414 return command->ServerErrorResponse( | |
| 415 "Tethering is used by another connection"); | |
| 416 } | |
| 417 DCHECK(impl_); | |
| 418 message_loop_proxy_->PostTask( | |
| 419 FROM_HERE, | |
| 420 base::Bind(&TetheringImpl::Unbind, base::Unretained(impl_), | |
| 421 command, port)); | |
| 422 return command->AsyncResponsePromise(); | |
| 423 } | |
| 424 | |
| 425 void TetheringHandler::SendBindSuccess( | |
| 426 scoped_refptr<DevToolsProtocol::Command> command) { | |
| 427 SendAsyncResponse(command->SuccessResponse(nullptr)); | |
| 428 } | |
| 429 | |
| 430 void TetheringHandler::SendUnbindSuccess( | |
| 431 scoped_refptr<DevToolsProtocol::Command> command) { | |
| 432 SendAsyncResponse(command->SuccessResponse(nullptr)); | |
| 433 } | |
| 434 | |
| 435 void TetheringHandler::SendInternalError( | |
| 436 scoped_refptr<DevToolsProtocol::Command> command, | |
| 437 const std::string& message) { | |
| 438 SendAsyncResponse(command->InternalErrorResponse(message)); | |
| 439 } | |
| 440 | |
| 441 } // namespace content | |
| OLD | NEW |