root/chrome/browser/devtools/adb/android_usb_socket.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. callback
  2. is_closed_
  3. HandleIncoming
  4. Terminated
  5. Read
  6. Write
  7. SetReceiveBufferSize
  8. SetSendBufferSize
  9. Connect
  10. Disconnect
  11. IsConnected
  12. IsConnectedAndIdle
  13. GetPeerAddress
  14. GetLocalAddress
  15. SetSubresourceSpeculation
  16. SetOmniboxSpeculation
  17. WasEverUsed
  18. UsingTCPFastOpen
  19. WasNpnNegotiated
  20. GetNegotiatedProtocol
  21. GetSSLInfo
  22. RespondToReaders
  23. RespondToWriters

// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/devtools/adb/android_usb_socket.h"

#include "base/message_loop/message_loop.h"

namespace {

const int kMaxPayload = 4096;

}  // namespace

AndroidUsbSocket::IORequest::IORequest(
    net::IOBuffer* buffer,
    int length,
    const net::CompletionCallback& callback)
    : buffer(buffer),
      length(length),
      callback(callback) {
}

AndroidUsbSocket::IORequest::~IORequest() {
}

AndroidUsbSocket::AndroidUsbSocket(scoped_refptr<AndroidUsbDevice> device,
                                   uint32 socket_id,
                                   const std::string& command,
                                   base::Callback<void(uint32)> delete_callback)
    : device_(device),
      command_(command),
      delete_callback_(delete_callback),
      local_id_(socket_id),
      remote_id_(0),
      is_connected_(false),
      is_closed_(false) {
}

AndroidUsbSocket::~AndroidUsbSocket() {
  DCHECK(CalledOnValidThread());
  if (is_connected_)
    Disconnect();
  delete_callback_.Run(local_id_);
}

void AndroidUsbSocket::HandleIncoming(scoped_refptr<AdbMessage> message) {
  CHECK_EQ(message->arg1, local_id_);
  switch (message->command) {
    case AdbMessage::kCommandOKAY:
      if (!is_connected_) {
        remote_id_ = message->arg0;
        is_connected_ = true;
        net::CompletionCallback callback = connect_callback_;
        connect_callback_.Reset();
        callback.Run(net::OK);
        // "this" can be NULL.
      } else {
        RespondToWriters();
        // "this" can be NULL.
      }
      break;
    case AdbMessage::kCommandWRTE:
      device_->Send(AdbMessage::kCommandOKAY, local_id_, message->arg0, "");
      read_buffer_ += message->body;
      // Allow WRTE over new connection even though OKAY ack was not received.
      if (!is_connected_) {
        remote_id_ = message->arg0;
        is_connected_ = true;
        net::CompletionCallback callback = connect_callback_;
        connect_callback_.Reset();
        callback.Run(net::OK);
        // "this" can be NULL.
      } else {
        RespondToReaders(false);
        // "this" can be NULL.
      }
      break;
    case AdbMessage::kCommandCLSE:
      if (is_connected_)
        device_->Send(AdbMessage::kCommandCLSE, local_id_, 0, "");
      is_connected_ = false;
      is_closed_ = true;
      RespondToReaders(true);
      // "this" can be NULL.
      break;
    default:
      break;
  }
}

void AndroidUsbSocket::Terminated() {
  is_connected_ = false;
  is_closed_ = true;
  if (!connect_callback_.is_null()) {
    net::CompletionCallback callback = connect_callback_;
    connect_callback_.Reset();
    callback.Run(net::ERR_FAILED);
    // "this" can be NULL.
    return;
  }
  RespondToReaders(true);
}

int AndroidUsbSocket::Read(net::IOBuffer* buffer,
                           int length,
                           const net::CompletionCallback& callback) {
  if (!is_connected_)
    return is_closed_ ? 0 : net::ERR_SOCKET_NOT_CONNECTED;

  if (read_buffer_.empty()) {
    read_requests_.push_back(IORequest(buffer, length, callback));
    return net::ERR_IO_PENDING;
  }

  size_t bytes_to_copy = static_cast<size_t>(length) > read_buffer_.length() ?
      read_buffer_.length() : static_cast<size_t>(length);
  memcpy(buffer->data(), read_buffer_.data(), bytes_to_copy);
  if (read_buffer_.length() > bytes_to_copy)
    read_buffer_ = read_buffer_.substr(bytes_to_copy);
  else
    read_buffer_ = "";
  return bytes_to_copy;
}

int AndroidUsbSocket::Write(net::IOBuffer* buffer,
                            int length,
                            const net::CompletionCallback& callback) {
  if (!is_connected_)
    return net::ERR_SOCKET_NOT_CONNECTED;

  if (length > kMaxPayload)
    length = kMaxPayload;
  write_requests_.push_back(IORequest(NULL, length, callback));
  device_->Send(AdbMessage::kCommandWRTE, local_id_, remote_id_,
                 std::string(buffer->data(), length));
  return net::ERR_IO_PENDING;
}

int AndroidUsbSocket::SetReceiveBufferSize(int32 size) {
  NOTIMPLEMENTED();
  return net::ERR_NOT_IMPLEMENTED;
}

int AndroidUsbSocket::SetSendBufferSize(int32 size) {
  NOTIMPLEMENTED();
  return net::ERR_NOT_IMPLEMENTED;
}

int AndroidUsbSocket::Connect(const net::CompletionCallback& callback) {
  DCHECK(CalledOnValidThread());
  if (device_->terminated())
    return net::ERR_FAILED;
  connect_callback_ = callback;
  device_->Send(AdbMessage::kCommandOPEN, local_id_, 0, command_);
  return net::ERR_IO_PENDING;
}

void AndroidUsbSocket::Disconnect() {
  is_connected_ = false;
  device_->Send(AdbMessage::kCommandCLSE, local_id_, remote_id_, "");
  RespondToReaders(true);
}

bool AndroidUsbSocket::IsConnected() const {
  DCHECK(CalledOnValidThread());
  return is_connected_;
}

bool AndroidUsbSocket::IsConnectedAndIdle() const {
  NOTIMPLEMENTED();
  return false;
}

int AndroidUsbSocket::GetPeerAddress(net::IPEndPoint* address) const {
  net::IPAddressNumber ip(net::kIPv4AddressSize);
  *address = net::IPEndPoint(ip, 0);
  return net::OK;
}

int AndroidUsbSocket::GetLocalAddress(net::IPEndPoint* address) const {
  NOTIMPLEMENTED();
  return net::ERR_NOT_IMPLEMENTED;
}

const net::BoundNetLog& AndroidUsbSocket::NetLog() const {
  return net_log_;
}

void AndroidUsbSocket::SetSubresourceSpeculation() {
  NOTIMPLEMENTED();
}

void AndroidUsbSocket::SetOmniboxSpeculation() {
  NOTIMPLEMENTED();
}

bool AndroidUsbSocket::WasEverUsed() const {
  NOTIMPLEMENTED();
  return true;
}

bool AndroidUsbSocket::UsingTCPFastOpen() const {
  NOTIMPLEMENTED();
  return true;
}

bool AndroidUsbSocket::WasNpnNegotiated() const {
  NOTIMPLEMENTED();
  return true;
}

net::NextProto AndroidUsbSocket::GetNegotiatedProtocol() const {
  NOTIMPLEMENTED();
  return net::kProtoUnknown;
}

bool AndroidUsbSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
  return false;
}

void AndroidUsbSocket::RespondToReaders(bool disconnect) {
  std::deque<IORequest> read_requests;
  read_requests.swap(read_requests_);
  while (!read_requests.empty() && (!read_buffer_.empty() || disconnect)) {
    IORequest read_request = read_requests.front();
    read_requests.pop_front();
    size_t bytes_to_copy =
        static_cast<size_t>(read_request.length) > read_buffer_.length() ?
            read_buffer_.length() : static_cast<size_t>(read_request.length);
    memcpy(read_request.buffer->data(), read_buffer_.data(), bytes_to_copy);
    if (read_buffer_.length() > bytes_to_copy)
      read_buffer_ = read_buffer_.substr(bytes_to_copy);
    else
      read_buffer_ = "";
    read_request.callback.Run(bytes_to_copy);
  }
}

void AndroidUsbSocket::RespondToWriters() {
  if (!write_requests_.empty()) {
    IORequest write_request = write_requests_.front();
    write_requests_.pop_front();
    write_request.callback.Run(write_request.length);
  }
}

/* [<][>][^][v][top][bottom][index][help] */