tethering_handler.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/public/browser/devtools_client_host.h"
13#include "content/public/browser/devtools_http_handler_delegate.h"
14#include "net/base/io_buffer.h"
15#include "net/base/ip_endpoint.h"
16#include "net/base/net_errors.h"
17#include "net/base/net_log.h"
18#include "net/socket/stream_listen_socket.h"
19#include "net/socket/stream_socket.h"
20#include "net/socket/tcp_server_socket.h"
21
22namespace content {
23
24namespace {
25
26const char kTetheringBind[] = "Tethering.bind";
27const char kTetheringUnbind[] = "Tethering.unbind";
28
29const char kTetheringAccepted[] = "Tethering.accepted";
30
31const char kPortParam[] = "port";
32const char kConnectionIdParam[] = "connectionId";
33
34const char kLocalhost[] = "127.0.0.1";
35
36const int kListenBacklog = 5;
37const int kBufferSize = 16 * 1024;
38
39const int kMinTetheringPort = 5000;
40const int kMaxTetheringPort = 10000;
41
42class SocketPump : public net::StreamListenSocket::Delegate {
43 public:
44  SocketPump(DevToolsHttpHandlerDelegate* delegate,
45             net::StreamSocket* client_socket)
46      : client_socket_(client_socket),
47        delegate_(delegate),
48        wire_buffer_size_(0),
49        pending_destruction_(false) {
50  }
51
52  std::string Init() {
53    std::string channel_name;
54    server_socket_ = delegate_->CreateSocketForTethering(this, &channel_name);
55    if (!server_socket_ || channel_name.empty())
56      SelfDestruct();
57    return channel_name;
58  }
59
60  virtual ~SocketPump() { }
61
62 private:
63  virtual void DidAccept(net::StreamListenSocket* server,
64                         net::StreamListenSocket* socket) OVERRIDE {
65    if (accepted_socket_)
66      return;
67
68    buffer_ = new net::IOBuffer(kBufferSize);
69    wire_buffer_ = new net::GrowableIOBuffer();
70    wire_buffer_->SetCapacity(kBufferSize);
71
72    accepted_socket_ = socket;
73    int result = client_socket_->Read(buffer_, kBufferSize,
74                                      base::Bind(&SocketPump::OnClientRead,
75                                                 base::Unretained(this)));
76    if (result != net::ERR_IO_PENDING)
77      OnClientRead(result);
78  }
79
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);
91  }
92
93  virtual void DidClose(net::StreamListenSocket* socket) OVERRIDE {
94    SelfDestruct();
95  }
96
97  void OnClientRead(int result) {
98    if (result <= 0) {
99      SelfDestruct();
100      return;
101    }
102
103    accepted_socket_->Send(buffer_->data(), result);
104    result = client_socket_->Read(buffer_, kBufferSize,
105                                  base::Bind(&SocketPump::OnClientRead,
106                                             base::Unretained(this)));
107    if (result != net::ERR_IO_PENDING)
108      OnClientRead(result);
109  }
110
111  void OnClientWrite(int result) {
112    if (result < 0)
113      SelfDestruct();
114
115    wire_buffer_->set_offset(wire_buffer_->offset() + result);
116
117    int remaining = wire_buffer_size_ - wire_buffer_->offset();
118    if (remaining == 0) {
119      if (pending_destruction_)
120        SelfDestruct();
121      return;
122    }
123
124
125    if (remaining > kBufferSize)
126      remaining = kBufferSize;
127
128    scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(remaining);
129    memcpy(buffer->data(), wire_buffer_->data(), remaining);
130    result = client_socket_->Write(
131        buffer, remaining, base::Bind(&SocketPump::OnClientWrite,
132                                      base::Unretained(this)));
133
134    // Shrink buffer
135    int offset = wire_buffer_->offset();
136    if (offset > kBufferSize) {
137      memcpy(wire_buffer_->StartOfBuffer(), wire_buffer_->data(),
138          wire_buffer_size_ - offset);
139      wire_buffer_size_ -= offset;
140      wire_buffer_->set_offset(0);
141    }
142
143    if (result != net::ERR_IO_PENDING)
144      OnClientWrite(result);
145    return;
146  }
147
148  void SelfDestruct() {
149    if (wire_buffer_->offset() != wire_buffer_size_) {
150      pending_destruction_ = true;
151      return;
152    }
153    delete this;
154  }
155
156 private:
157  scoped_ptr<net::StreamSocket> client_socket_;
158  scoped_refptr<net::StreamListenSocket> server_socket_;
159  scoped_refptr<net::StreamListenSocket> accepted_socket_;
160  scoped_refptr<net::IOBuffer> buffer_;
161  scoped_refptr<net::GrowableIOBuffer> wire_buffer_;
162  DevToolsHttpHandlerDelegate* delegate_;
163  int wire_buffer_size_;
164  bool pending_destruction_;
165};
166
167}  // namespace
168
169const char TetheringHandler::kDomain[] = "Tethering";
170
171class TetheringHandler::BoundSocket {
172 public:
173  BoundSocket(TetheringHandler* handler,
174              DevToolsHttpHandlerDelegate* delegate)
175      : handler_(handler),
176        delegate_(delegate),
177        socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
178        port_(0) {
179  }
180
181  virtual ~BoundSocket() {
182  }
183
184  bool Listen(int port) {
185    port_ = port;
186    net::IPAddressNumber ip_number;
187    if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
188      return false;
189
190    net::IPEndPoint end_point(ip_number, port);
191    socket_->AllowAddressReuse();
192    int result = socket_->Listen(end_point, kListenBacklog);
193    if (result < 0)
194      return false;
195
196    net::IPEndPoint local_address;
197    result = socket_->GetLocalAddress(&local_address);
198    if (result < 0)
199      return false;
200
201    DoAccept();
202    return true;
203  }
204
205 private:
206  typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
207
208  void DoAccept() {
209    while (true) {
210      int result = socket_->Accept(
211          &accept_socket_,
212          base::Bind(&BoundSocket::OnAccepted, base::Unretained(this)));
213      if (result == net::ERR_IO_PENDING)
214        break;
215      else
216        HandleAcceptResult(result);
217    }
218  }
219
220  void OnAccepted(int result) {
221    HandleAcceptResult(result);
222    if (result == net::OK)
223      DoAccept();
224  }
225
226  void HandleAcceptResult(int result) {
227    if (result != net::OK)
228      return;
229
230    SocketPump* pump = new SocketPump(delegate_, accept_socket_.release());
231    std::string name = pump->Init();
232    if (!name.empty())
233      handler_->Accepted(port_, name);
234  }
235
236  TetheringHandler* handler_;
237  DevToolsHttpHandlerDelegate* delegate_;
238  scoped_ptr<net::ServerSocket> socket_;
239  scoped_ptr<net::StreamSocket> accept_socket_;
240  int port_;
241};
242
243TetheringHandler::TetheringHandler(DevToolsHttpHandlerDelegate* delegate)
244    : delegate_(delegate) {
245  RegisterCommandHandler(kTetheringBind,
246                         base::Bind(&TetheringHandler::OnBind,
247                                    base::Unretained(this)));
248  RegisterCommandHandler(kTetheringUnbind,
249                         base::Bind(&TetheringHandler::OnUnbind,
250                                    base::Unretained(this)));
251}
252
253TetheringHandler::~TetheringHandler() {
254   STLDeleteContainerPairSecondPointers(bound_sockets_.begin(),
255                                        bound_sockets_.end());
256}
257
258void TetheringHandler::Accepted(int port, const std::string& name) {
259  base::DictionaryValue* params = new base::DictionaryValue();
260  params->SetInteger(kPortParam, port);
261  params->SetString(kConnectionIdParam, name);
262  SendNotification(kTetheringAccepted, params);
263}
264
265static int GetPort(DevToolsProtocol::Command* command) {
266  base::DictionaryValue* params = command->params();
267  int port = 0;
268  if (!params || !params->GetInteger(kPortParam, &port) ||
269      port < kMinTetheringPort || port > kMaxTetheringPort)
270    return 0;
271  return port;
272}
273
274scoped_ptr<DevToolsProtocol::Response>
275TetheringHandler::OnBind(DevToolsProtocol::Command* command) {
276  int port = GetPort(command);
277  if (port == 0)
278    return command->InvalidParamResponse(kPortParam);
279
280  if (bound_sockets_.find(port) != bound_sockets_.end())
281    return command->InternalErrorResponse("Port already bound");
282
283  scoped_ptr<BoundSocket> bound_socket(new BoundSocket(this, delegate_));
284  if (!bound_socket->Listen(port))
285    return command->InternalErrorResponse("Could not bind port");
286
287  bound_sockets_[port] = bound_socket.release();
288  return command->SuccessResponse(NULL);
289}
290
291scoped_ptr<DevToolsProtocol::Response>
292TetheringHandler::OnUnbind(DevToolsProtocol::Command* command) {
293  int port = GetPort(command);
294  if (port == 0)
295    return command->InvalidParamResponse(kPortParam);
296
297  BoundSockets::iterator it = bound_sockets_.find(port);
298  if (it == bound_sockets_.end())
299    return command->InternalErrorResponse("Port is not bound");
300
301  delete it->second;
302  bound_sockets_.erase(it);
303  return command->SuccessResponse(NULL);
304}
305
306}  // namespace content
307