普通文本  |  313行  |  9.6 KB

// Copyright 2014 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 "device/bluetooth/bluetooth_socket_net.h"

#include <queue>
#include <string>

#include "base/logging.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/thread_restrictions.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "device/bluetooth/bluetooth_socket_thread.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"

namespace {

const char kSocketNotConnected[] = "Socket is not connected.";

static void DeactivateSocket(
    const scoped_refptr<device::BluetoothSocketThread>& socket_thread) {
  socket_thread->OnSocketDeactivate();
}

}  // namespace

namespace device {

BluetoothSocketNet::WriteRequest::WriteRequest()
    : buffer_size(0) {}

BluetoothSocketNet::WriteRequest::~WriteRequest() {}

BluetoothSocketNet::BluetoothSocketNet(
    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
    scoped_refptr<BluetoothSocketThread> socket_thread,
    net::NetLog* net_log,
    const net::NetLog::Source& source)
    : ui_task_runner_(ui_task_runner),
      socket_thread_(socket_thread),
      net_log_(net_log),
      source_(source) {
  DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
  socket_thread_->OnSocketActivate();
}

BluetoothSocketNet::~BluetoothSocketNet() {
  DCHECK(tcp_socket_.get() == NULL);
  ui_task_runner_->PostTask(FROM_HERE,
                            base::Bind(&DeactivateSocket, socket_thread_));
}

void BluetoothSocketNet::Close() {
  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
  socket_thread_->task_runner()->PostTask(
      FROM_HERE, base::Bind(&BluetoothSocketNet::DoClose, this));
}

void BluetoothSocketNet::Disconnect(
    const base::Closure& success_callback) {
  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
  socket_thread_->task_runner()->PostTask(
      FROM_HERE,
      base::Bind(
          &BluetoothSocketNet::DoDisconnect,
          this,
          base::Bind(&BluetoothSocketNet::PostSuccess,
                     this,
                     success_callback)));
}

void BluetoothSocketNet::Receive(
    int buffer_size,
    const ReceiveCompletionCallback& success_callback,
    const ReceiveErrorCompletionCallback& error_callback) {
  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
  socket_thread_->task_runner()->PostTask(
      FROM_HERE,
      base::Bind(
          &BluetoothSocketNet::DoReceive,
          this,
          buffer_size,
          base::Bind(&BluetoothSocketNet::PostReceiveCompletion,
                     this,
                     success_callback),
          base::Bind(&BluetoothSocketNet::PostReceiveErrorCompletion,
                     this,
                     error_callback)));
}

void BluetoothSocketNet::Send(
    scoped_refptr<net::IOBuffer> buffer,
    int buffer_size,
    const SendCompletionCallback& success_callback,
    const ErrorCompletionCallback& error_callback) {
  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
  socket_thread_->task_runner()->PostTask(
      FROM_HERE,
      base::Bind(
          &BluetoothSocketNet::DoSend,
          this,
          buffer,
          buffer_size,
          base::Bind(&BluetoothSocketNet::PostSendCompletion,
                     this,
                     success_callback),
          base::Bind(&BluetoothSocketNet::PostErrorCompletion,
                     this,
                     error_callback)));
}

void BluetoothSocketNet::ResetData() {
}

void BluetoothSocketNet::ResetTCPSocket() {
  tcp_socket_.reset(new net::TCPSocket(net_log_, source_));
}

void BluetoothSocketNet::SetTCPSocket(scoped_ptr<net::TCPSocket> tcp_socket) {
  tcp_socket_ = tcp_socket.Pass();
}

void BluetoothSocketNet::PostSuccess(const base::Closure& callback) {
  ui_task_runner_->PostTask(FROM_HERE, callback);
}

void BluetoothSocketNet::PostErrorCompletion(
    const ErrorCompletionCallback& callback,
    const std::string& error) {
  ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, error));
}

void BluetoothSocketNet::DoClose() {
  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
  base::ThreadRestrictions::AssertIOAllowed();

  if (tcp_socket_) {
    tcp_socket_->Close();
    tcp_socket_.reset(NULL);
  }

  // Note: Closing |tcp_socket_| above released all potential pending
  // Send/Receive operations, so we can no safely release the state associated
  // to those pending operations.
  read_buffer_ = NULL;
  std::queue<linked_ptr<WriteRequest> > empty;
  std::swap(write_queue_, empty);

  ResetData();
}

void BluetoothSocketNet::DoDisconnect(const base::Closure& callback) {
  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
  base::ThreadRestrictions::AssertIOAllowed();

  DoClose();
  callback.Run();
}

void BluetoothSocketNet::DoReceive(
    int buffer_size,
    const ReceiveCompletionCallback& success_callback,
    const ReceiveErrorCompletionCallback& error_callback) {
  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
  base::ThreadRestrictions::AssertIOAllowed();

  if (!tcp_socket_) {
    error_callback.Run(BluetoothSocket::kDisconnected, kSocketNotConnected);
    return;
  }

  // Only one pending read at a time
  if (read_buffer_.get()) {
    error_callback.Run(BluetoothSocket::kIOPending,
                       net::ErrorToString(net::ERR_IO_PENDING));
    return;
  }

  scoped_refptr<net::IOBufferWithSize> buffer(
      new net::IOBufferWithSize(buffer_size));
  int read_result =
      tcp_socket_->Read(buffer.get(),
                        buffer->size(),
                        base::Bind(&BluetoothSocketNet::OnSocketReadComplete,
                                   this,
                                   success_callback,
                                   error_callback));

  read_buffer_ = buffer;
  if (read_result != net::ERR_IO_PENDING)
    OnSocketReadComplete(success_callback, error_callback, read_result);
}

void BluetoothSocketNet::OnSocketReadComplete(
    const ReceiveCompletionCallback& success_callback,
    const ReceiveErrorCompletionCallback& error_callback,
    int read_result) {
  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
  base::ThreadRestrictions::AssertIOAllowed();

  scoped_refptr<net::IOBufferWithSize> buffer;
  buffer.swap(read_buffer_);
  if (read_result > 0) {
    success_callback.Run(read_result, buffer);
  } else if (read_result == net::OK ||
             read_result == net::ERR_CONNECTION_CLOSED ||
             read_result == net::ERR_CONNECTION_RESET) {
    error_callback.Run(BluetoothSocket::kDisconnected,
                       net::ErrorToString(read_result));
  } else {
    error_callback.Run(BluetoothSocket::kSystemError,
                       net::ErrorToString(read_result));
  }
}

void BluetoothSocketNet::DoSend(
    scoped_refptr<net::IOBuffer> buffer,
    int buffer_size,
    const SendCompletionCallback& success_callback,
    const ErrorCompletionCallback& error_callback) {
  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
  base::ThreadRestrictions::AssertIOAllowed();

  if (!tcp_socket_) {
    error_callback.Run(kSocketNotConnected);
    return;
  }

  linked_ptr<WriteRequest> request(new WriteRequest());
  request->buffer = buffer;
  request->buffer_size = buffer_size;
  request->success_callback = success_callback;
  request->error_callback = error_callback;

  write_queue_.push(request);
  if (write_queue_.size() == 1) {
    SendFrontWriteRequest();
  }
}

void BluetoothSocketNet::SendFrontWriteRequest() {
  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
  base::ThreadRestrictions::AssertIOAllowed();

  if (!tcp_socket_)
    return;

  if (write_queue_.size() == 0)
    return;

  linked_ptr<WriteRequest> request = write_queue_.front();
  net::CompletionCallback callback =
      base::Bind(&BluetoothSocketNet::OnSocketWriteComplete,
                 this,
                 request->success_callback,
                 request->error_callback);
  int send_result =
      tcp_socket_->Write(request->buffer, request->buffer_size, callback);
  if (send_result != net::ERR_IO_PENDING) {
    callback.Run(send_result);
  }
}

void BluetoothSocketNet::OnSocketWriteComplete(
    const SendCompletionCallback& success_callback,
    const ErrorCompletionCallback& error_callback,
    int send_result) {
  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
  base::ThreadRestrictions::AssertIOAllowed();

  write_queue_.pop();

  if (send_result >= net::OK) {
    success_callback.Run(send_result);
  } else {
    error_callback.Run(net::ErrorToString(send_result));
  }

  // Don't call directly to avoid potentail large recursion.
  socket_thread_->task_runner()->PostNonNestableTask(
      FROM_HERE,
      base::Bind(&BluetoothSocketNet::SendFrontWriteRequest, this));
}

void BluetoothSocketNet::PostReceiveCompletion(
    const ReceiveCompletionCallback& callback,
    int io_buffer_size,
    scoped_refptr<net::IOBuffer> io_buffer) {
  ui_task_runner_->PostTask(FROM_HERE,
                            base::Bind(callback, io_buffer_size, io_buffer));
}

void BluetoothSocketNet::PostReceiveErrorCompletion(
    const ReceiveErrorCompletionCallback& callback,
    ErrorReason reason,
    const std::string& error_message) {
  ui_task_runner_->PostTask(FROM_HERE,
                            base::Bind(callback, reason, error_message));
}

void BluetoothSocketNet::PostSendCompletion(
    const SendCompletionCallback& callback,
    int bytes_written) {
  ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written));
}

}  // namespace device