Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / devtools / tethering_handler.cc
bloba567797c1f584a2c642cc86285a44bba7f18b0d1
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.
5 #include "content/browser/devtools/tethering_handler.h"
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/public/browser/devtools_http_handler_delegate.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/ip_endpoint.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/net_log.h"
17 #include "net/socket/stream_listen_socket.h"
18 #include "net/socket/stream_socket.h"
19 #include "net/socket/tcp_server_socket.h"
21 namespace content {
23 namespace {
25 const char kTetheringBind[] = "Tethering.bind";
26 const char kTetheringUnbind[] = "Tethering.unbind";
28 const char kTetheringAccepted[] = "Tethering.accepted";
30 const char kPortParam[] = "port";
31 const char kConnectionIdParam[] = "connectionId";
33 const char kLocalhost[] = "127.0.0.1";
35 const int kListenBacklog = 5;
36 const int kBufferSize = 16 * 1024;
38 const int kMinTetheringPort = 5000;
39 const int kMaxTetheringPort = 10000;
41 class SocketPump : public net::StreamListenSocket::Delegate {
42 public:
43 SocketPump(DevToolsHttpHandlerDelegate* delegate,
44 net::StreamSocket* client_socket)
45 : client_socket_(client_socket),
46 delegate_(delegate),
47 wire_buffer_size_(0),
48 pending_destruction_(false) {
51 std::string Init() {
52 std::string channel_name;
53 server_socket_ = delegate_->CreateSocketForTethering(this, &channel_name);
54 if (!server_socket_.get() || channel_name.empty())
55 SelfDestruct();
56 return channel_name;
59 virtual ~SocketPump() { }
61 private:
62 virtual void DidAccept(net::StreamListenSocket* server,
63 scoped_ptr<net::StreamListenSocket> socket) OVERRIDE {
64 if (accepted_socket_.get())
65 return;
67 buffer_ = new net::IOBuffer(kBufferSize);
68 wire_buffer_ = new net::GrowableIOBuffer();
69 wire_buffer_->SetCapacity(kBufferSize);
71 accepted_socket_ = socket.Pass();
72 int result = client_socket_->Read(
73 buffer_.get(),
74 kBufferSize,
75 base::Bind(&SocketPump::OnClientRead, base::Unretained(this)));
76 if (result != net::ERR_IO_PENDING)
77 OnClientRead(result);
80 virtual void DidRead(net::StreamListenSocket* socket,
81 const char* data,
82 int len) OVERRIDE {
83 int old_size = wire_buffer_size_;
84 wire_buffer_size_ += len;
85 while (wire_buffer_->capacity() < wire_buffer_size_)
86 wire_buffer_->SetCapacity(wire_buffer_->capacity() * 2);
87 memcpy(wire_buffer_->StartOfBuffer() + old_size, data, len);
88 if (old_size != wire_buffer_->offset())
89 return;
90 OnClientWrite(0);
93 virtual void DidClose(net::StreamListenSocket* socket) OVERRIDE {
94 SelfDestruct();
97 void OnClientRead(int result) {
98 if (result <= 0) {
99 SelfDestruct();
100 return;
103 accepted_socket_->Send(buffer_->data(), result);
104 result = client_socket_->Read(
105 buffer_.get(),
106 kBufferSize,
107 base::Bind(&SocketPump::OnClientRead, base::Unretained(this)));
108 if (result != net::ERR_IO_PENDING)
109 OnClientRead(result);
112 void OnClientWrite(int result) {
113 if (result < 0) {
114 SelfDestruct();
115 return;
118 wire_buffer_->set_offset(wire_buffer_->offset() + result);
120 int remaining = wire_buffer_size_ - wire_buffer_->offset();
121 if (remaining == 0) {
122 if (pending_destruction_)
123 SelfDestruct();
124 return;
128 if (remaining > kBufferSize)
129 remaining = kBufferSize;
131 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(remaining);
132 memcpy(buffer->data(), wire_buffer_->data(), remaining);
133 result = client_socket_->Write(
134 buffer.get(),
135 remaining,
136 base::Bind(&SocketPump::OnClientWrite, base::Unretained(this)));
138 // Shrink buffer
139 int offset = wire_buffer_->offset();
140 if (offset > kBufferSize) {
141 memcpy(wire_buffer_->StartOfBuffer(), wire_buffer_->data(),
142 wire_buffer_size_ - offset);
143 wire_buffer_size_ -= offset;
144 wire_buffer_->set_offset(0);
147 if (result != net::ERR_IO_PENDING)
148 OnClientWrite(result);
149 return;
152 void SelfDestruct() {
153 if (wire_buffer_.get() && wire_buffer_->offset() != wire_buffer_size_) {
154 pending_destruction_ = true;
155 return;
157 delete this;
160 private:
161 scoped_ptr<net::StreamSocket> client_socket_;
162 scoped_ptr<net::StreamListenSocket> server_socket_;
163 scoped_ptr<net::StreamListenSocket> accepted_socket_;
164 scoped_refptr<net::IOBuffer> buffer_;
165 scoped_refptr<net::GrowableIOBuffer> wire_buffer_;
166 DevToolsHttpHandlerDelegate* delegate_;
167 int wire_buffer_size_;
168 bool pending_destruction_;
171 } // namespace
173 const char TetheringHandler::kDomain[] = "Tethering";
175 class TetheringHandler::BoundSocket {
176 public:
177 BoundSocket(TetheringHandler* handler,
178 DevToolsHttpHandlerDelegate* delegate)
179 : handler_(handler),
180 delegate_(delegate),
181 socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
182 port_(0) {
185 virtual ~BoundSocket() {
188 bool Listen(int port) {
189 port_ = port;
190 net::IPAddressNumber ip_number;
191 if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
192 return false;
194 net::IPEndPoint end_point(ip_number, port);
195 int result = socket_->Listen(end_point, kListenBacklog);
196 if (result < 0)
197 return false;
199 net::IPEndPoint local_address;
200 result = socket_->GetLocalAddress(&local_address);
201 if (result < 0)
202 return false;
204 DoAccept();
205 return true;
208 private:
209 typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
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);
223 void OnAccepted(int result) {
224 HandleAcceptResult(result);
225 if (result == net::OK)
226 DoAccept();
229 void HandleAcceptResult(int result) {
230 if (result != net::OK)
231 return;
233 SocketPump* pump = new SocketPump(delegate_, accept_socket_.release());
234 std::string name = pump->Init();
235 if (!name.empty())
236 handler_->Accepted(port_, name);
239 TetheringHandler* handler_;
240 DevToolsHttpHandlerDelegate* delegate_;
241 scoped_ptr<net::ServerSocket> socket_;
242 scoped_ptr<net::StreamSocket> accept_socket_;
243 int port_;
246 TetheringHandler::TetheringHandler(DevToolsHttpHandlerDelegate* delegate)
247 : delegate_(delegate) {
248 RegisterCommandHandler(kTetheringBind,
249 base::Bind(&TetheringHandler::OnBind,
250 base::Unretained(this)));
251 RegisterCommandHandler(kTetheringUnbind,
252 base::Bind(&TetheringHandler::OnUnbind,
253 base::Unretained(this)));
256 TetheringHandler::~TetheringHandler() {
257 STLDeleteContainerPairSecondPointers(bound_sockets_.begin(),
258 bound_sockets_.end());
261 void TetheringHandler::Accepted(int port, const std::string& name) {
262 base::DictionaryValue* params = new base::DictionaryValue();
263 params->SetInteger(kPortParam, port);
264 params->SetString(kConnectionIdParam, name);
265 SendNotification(kTetheringAccepted, params);
268 static int GetPort(scoped_refptr<DevToolsProtocol::Command> command) {
269 base::DictionaryValue* params = command->params();
270 int port = 0;
271 if (!params || !params->GetInteger(kPortParam, &port) ||
272 port < kMinTetheringPort || port > kMaxTetheringPort)
273 return 0;
274 return port;
277 scoped_refptr<DevToolsProtocol::Response>
278 TetheringHandler::OnBind(scoped_refptr<DevToolsProtocol::Command> command) {
279 int port = GetPort(command);
280 if (port == 0)
281 return command->InvalidParamResponse(kPortParam);
283 if (bound_sockets_.find(port) != bound_sockets_.end())
284 return command->InternalErrorResponse("Port already bound");
286 scoped_ptr<BoundSocket> bound_socket(new BoundSocket(this, delegate_));
287 if (!bound_socket->Listen(port))
288 return command->InternalErrorResponse("Could not bind port");
290 bound_sockets_[port] = bound_socket.release();
291 return command->SuccessResponse(NULL);
294 scoped_refptr<DevToolsProtocol::Response>
295 TetheringHandler::OnUnbind(scoped_refptr<DevToolsProtocol::Command> command) {
296 int port = GetPort(command);
297 if (port == 0)
298 return command->InvalidParamResponse(kPortParam);
300 BoundSockets::iterator it = bound_sockets_.find(port);
301 if (it == bound_sockets_.end())
302 return command->InternalErrorResponse("Port is not bound");
304 delete it->second;
305 bound_sockets_.erase(it);
306 return command->SuccessResponse(NULL);
309 } // namespace content