summaryrefslogtreecommitdiffstats
path: root/device/bluetooth/bluetooth_socket_net.cc
diff options
context:
space:
mode:
authorkeybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-02 16:07:31 +0000
committerkeybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-02 16:07:31 +0000
commit2c24d9436912ec660b810dc0ad980b65155c8252 (patch)
treee465dac2d5aa7d2a9621181eb3d8349ee038f9d1 /device/bluetooth/bluetooth_socket_net.cc
parent640c6dbcde383305d960e3a9b0a40a09e3910a1e (diff)
downloadchromium_src-2c24d9436912ec660b810dc0ad980b65155c8252.zip
chromium_src-2c24d9436912ec660b810dc0ad980b65155c8252.tar.gz
chromium_src-2c24d9436912ec660b810dc0ad980b65155c8252.tar.bz2
Reimplement BluetoothSocketChromeOS
Since Chrome OS uses a socket-based interface much of the code already in BluetoothSocketWin is suitable. Separate out that common code into a new BluetoothSocketNet class and have both implementations derive from that class with their differing Connect implementations remaining separate. BUG=362613 Review URL: https://codereview.chromium.org/267633003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267804 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device/bluetooth/bluetooth_socket_net.cc')
-rw-r--r--device/bluetooth/bluetooth_socket_net.cc333
1 files changed, 333 insertions, 0 deletions
diff --git a/device/bluetooth/bluetooth_socket_net.cc b/device/bluetooth/bluetooth_socket_net.cc
new file mode 100644
index 0000000..8360578
--- /dev/null
+++ b/device/bluetooth/bluetooth_socket_net.cc
@@ -0,0 +1,333 @@
+// 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 {
+
+// static
+scoped_refptr<BluetoothSocketNet>
+BluetoothSocketNet::CreateBluetoothSocket(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+ scoped_refptr<BluetoothSocketThread> socket_thread,
+ net::NetLog* net_log,
+ const net::NetLog::Source& source) {
+ DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
+
+ return make_scoped_refptr(
+ new BluetoothSocketNet(ui_task_runner, socket_thread, net_log, source));
+}
+
+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));
+
+ if (read_result > 0) {
+ success_callback.Run(read_result, buffer);
+ } else if (read_result == net::OK ||
+ read_result == net::ERR_CONNECTION_CLOSED) {
+ error_callback.Run(BluetoothSocket::kDisconnected,
+ net::ErrorToString(net::ERR_CONNECTION_CLOSED));
+ } else if (read_result == net::ERR_IO_PENDING) {
+ read_buffer_ = buffer;
+ } else {
+ error_callback.Run(BluetoothSocket::kSystemError,
+ net::ErrorToString(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) {
+ error_callback.Run(BluetoothSocket::kDisconnected,
+ net::ErrorToString(net::ERR_CONNECTION_CLOSED));
+ } 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