android_usb_socket.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2014 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 "chrome/browser/devtools/device/usb/android_usb_socket.h"
6
7#include "base/message_loop/message_loop.h"
8
9namespace {
10
11const int kMaxPayload = 4096;
12
13}  // namespace
14
15AndroidUsbSocket::IORequest::IORequest(
16    net::IOBuffer* buffer,
17    int length,
18    const net::CompletionCallback& callback)
19    : buffer(buffer),
20      length(length),
21      callback(callback) {
22}
23
24AndroidUsbSocket::IORequest::~IORequest() {
25}
26
27AndroidUsbSocket::AndroidUsbSocket(scoped_refptr<AndroidUsbDevice> device,
28                                   uint32 socket_id,
29                                   const std::string& command,
30                                   base::Callback<void(uint32)> delete_callback)
31    : device_(device),
32      command_(command),
33      delete_callback_(delete_callback),
34      local_id_(socket_id),
35      remote_id_(0),
36      is_connected_(false) {
37}
38
39AndroidUsbSocket::~AndroidUsbSocket() {
40  DCHECK(CalledOnValidThread());
41  if (is_connected_)
42    Disconnect();
43  if (!delete_callback_.is_null())
44    delete_callback_.Run(local_id_);
45}
46
47void AndroidUsbSocket::HandleIncoming(scoped_refptr<AdbMessage> message) {
48  if (!device_.get())
49    return;
50
51  CHECK_EQ(message->arg1, local_id_);
52  switch (message->command) {
53    case AdbMessage::kCommandOKAY:
54      if (!is_connected_) {
55        remote_id_ = message->arg0;
56        is_connected_ = true;
57        net::CompletionCallback callback = connect_callback_;
58        connect_callback_.Reset();
59        callback.Run(net::OK);
60        // "this" can be NULL.
61      } else {
62        RespondToWriters();
63        // "this" can be NULL.
64      }
65      break;
66    case AdbMessage::kCommandWRTE:
67      device_->Send(AdbMessage::kCommandOKAY, local_id_, message->arg0, "");
68      read_buffer_ += message->body;
69      // Allow WRTE over new connection even though OKAY ack was not received.
70      if (!is_connected_) {
71        remote_id_ = message->arg0;
72        is_connected_ = true;
73        net::CompletionCallback callback = connect_callback_;
74        connect_callback_.Reset();
75        callback.Run(net::OK);
76        // "this" can be NULL.
77      } else {
78        RespondToReaders(false);
79        // "this" can be NULL.
80      }
81      break;
82    case AdbMessage::kCommandCLSE:
83      if (is_connected_)
84        device_->Send(AdbMessage::kCommandCLSE, local_id_, 0, "");
85      Terminated(true);
86      // "this" can be NULL.
87      break;
88    default:
89      break;
90  }
91}
92
93void AndroidUsbSocket::Terminated(bool closed_by_device) {
94  is_connected_ = false;
95
96  // Break the socket -> device connection, release the device.
97  delete_callback_.Run(local_id_);
98  delete_callback_.Reset();
99  device_ = NULL;
100
101  if (!closed_by_device)
102    return;
103
104  // Respond to pending callbacks.
105  if (!connect_callback_.is_null()) {
106    net::CompletionCallback callback = connect_callback_;
107    connect_callback_.Reset();
108    callback.Run(net::ERR_FAILED);
109    // "this" can be NULL.
110    return;
111  }
112  RespondToReaders(true);
113}
114
115int AndroidUsbSocket::Read(net::IOBuffer* buffer,
116                           int length,
117                           const net::CompletionCallback& callback) {
118  if (!is_connected_)
119    return device_.get() ? net::ERR_SOCKET_NOT_CONNECTED : 0;
120
121  if (read_buffer_.empty()) {
122    read_requests_.push_back(IORequest(buffer, length, callback));
123    return net::ERR_IO_PENDING;
124  }
125
126  size_t bytes_to_copy = static_cast<size_t>(length) > read_buffer_.length() ?
127      read_buffer_.length() : static_cast<size_t>(length);
128  memcpy(buffer->data(), read_buffer_.data(), bytes_to_copy);
129  if (read_buffer_.length() > bytes_to_copy)
130    read_buffer_ = read_buffer_.substr(bytes_to_copy);
131  else
132    read_buffer_ = "";
133  return bytes_to_copy;
134}
135
136int AndroidUsbSocket::Write(net::IOBuffer* buffer,
137                            int length,
138                            const net::CompletionCallback& callback) {
139  if (!is_connected_)
140    return net::ERR_SOCKET_NOT_CONNECTED;
141
142  if (length > kMaxPayload)
143    length = kMaxPayload;
144  write_requests_.push_back(IORequest(NULL, length, callback));
145  device_->Send(AdbMessage::kCommandWRTE, local_id_, remote_id_,
146                 std::string(buffer->data(), length));
147  return net::ERR_IO_PENDING;
148}
149
150int AndroidUsbSocket::SetReceiveBufferSize(int32 size) {
151  NOTIMPLEMENTED();
152  return net::ERR_NOT_IMPLEMENTED;
153}
154
155int AndroidUsbSocket::SetSendBufferSize(int32 size) {
156  NOTIMPLEMENTED();
157  return net::ERR_NOT_IMPLEMENTED;
158}
159
160int AndroidUsbSocket::Connect(const net::CompletionCallback& callback) {
161  DCHECK(CalledOnValidThread());
162  if (!device_.get())
163    return net::ERR_FAILED;
164  connect_callback_ = callback;
165  device_->Send(AdbMessage::kCommandOPEN, local_id_, 0, command_);
166  return net::ERR_IO_PENDING;
167}
168
169void AndroidUsbSocket::Disconnect() {
170  if (!device_.get())
171    return;
172  device_->Send(AdbMessage::kCommandCLSE, local_id_, remote_id_, "");
173  Terminated(false);
174}
175
176bool AndroidUsbSocket::IsConnected() const {
177  DCHECK(CalledOnValidThread());
178  return is_connected_;
179}
180
181bool AndroidUsbSocket::IsConnectedAndIdle() const {
182  NOTIMPLEMENTED();
183  return false;
184}
185
186int AndroidUsbSocket::GetPeerAddress(net::IPEndPoint* address) const {
187  net::IPAddressNumber ip(net::kIPv4AddressSize);
188  *address = net::IPEndPoint(ip, 0);
189  return net::OK;
190}
191
192int AndroidUsbSocket::GetLocalAddress(net::IPEndPoint* address) const {
193  NOTIMPLEMENTED();
194  return net::ERR_NOT_IMPLEMENTED;
195}
196
197const net::BoundNetLog& AndroidUsbSocket::NetLog() const {
198  return net_log_;
199}
200
201void AndroidUsbSocket::SetSubresourceSpeculation() {
202  NOTIMPLEMENTED();
203}
204
205void AndroidUsbSocket::SetOmniboxSpeculation() {
206  NOTIMPLEMENTED();
207}
208
209bool AndroidUsbSocket::WasEverUsed() const {
210  NOTIMPLEMENTED();
211  return true;
212}
213
214bool AndroidUsbSocket::UsingTCPFastOpen() const {
215  NOTIMPLEMENTED();
216  return true;
217}
218
219bool AndroidUsbSocket::WasNpnNegotiated() const {
220  NOTIMPLEMENTED();
221  return true;
222}
223
224net::NextProto AndroidUsbSocket::GetNegotiatedProtocol() const {
225  NOTIMPLEMENTED();
226  return net::kProtoUnknown;
227}
228
229bool AndroidUsbSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
230  return false;
231}
232
233void AndroidUsbSocket::RespondToReaders(bool disconnect) {
234  std::deque<IORequest> read_requests;
235  read_requests.swap(read_requests_);
236  while (!read_requests.empty() && (!read_buffer_.empty() || disconnect)) {
237    IORequest read_request = read_requests.front();
238    read_requests.pop_front();
239    size_t bytes_to_copy =
240        static_cast<size_t>(read_request.length) > read_buffer_.length() ?
241            read_buffer_.length() : static_cast<size_t>(read_request.length);
242    memcpy(read_request.buffer->data(), read_buffer_.data(), bytes_to_copy);
243    if (read_buffer_.length() > bytes_to_copy)
244      read_buffer_ = read_buffer_.substr(bytes_to_copy);
245    else
246      read_buffer_ = "";
247    read_request.callback.Run(bytes_to_copy);
248  }
249}
250
251void AndroidUsbSocket::RespondToWriters() {
252  if (!write_requests_.empty()) {
253    IORequest write_request = write_requests_.front();
254    write_requests_.pop_front();
255    write_request.callback.Run(write_request.length);
256  }
257}
258