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