blob: bb69ac9e3b2461ba8700511b7c510453f21d8c90 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/lazy_instance.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "net/base/io_buffer.h"
namespace {
const char kSocketNotConnectedError[] = "Socket not connected";
const char kSocketNotListeningError[] = "Socket not listening";
} // namespace
namespace extensions {
// static
static base::LazyInstance<BrowserContextKeyedAPIFactory<
ApiResourceManager<BluetoothApiSocket>>>::DestructorAtExit
g_server_factory = LAZY_INSTANCE_INITIALIZER;
// static
template <>
BrowserContextKeyedAPIFactory<ApiResourceManager<BluetoothApiSocket> >*
ApiResourceManager<BluetoothApiSocket>::GetFactoryInstance() {
return g_server_factory.Pointer();
}
BluetoothApiSocket::BluetoothApiSocket(const std::string& owner_extension_id)
: ApiResource(owner_extension_id),
persistent_(false),
buffer_size_(0),
paused_(false),
connected_(false) {
DCHECK_CURRENTLY_ON(kThreadId);
}
BluetoothApiSocket::BluetoothApiSocket(
const std::string& owner_extension_id,
scoped_refptr<device::BluetoothSocket> socket,
const std::string& device_address,
const device::BluetoothUUID& uuid)
: ApiResource(owner_extension_id),
socket_(socket),
device_address_(device_address),
uuid_(uuid),
persistent_(false),
buffer_size_(0),
paused_(true),
connected_(true) {
DCHECK_CURRENTLY_ON(kThreadId);
}
BluetoothApiSocket::~BluetoothApiSocket() {
DCHECK_CURRENTLY_ON(kThreadId);
if (socket_.get()) {
socket_->Disconnect(base::DoNothing());
}
}
void BluetoothApiSocket::AdoptConnectedSocket(
scoped_refptr<device::BluetoothSocket> socket,
const std::string& device_address,
const device::BluetoothUUID& uuid) {
DCHECK_CURRENTLY_ON(kThreadId);
if (socket_.get()) {
socket_->Disconnect(base::DoNothing());
}
socket_ = socket;
device_address_ = device_address;
uuid_ = uuid;
connected_ = true;
}
void BluetoothApiSocket::AdoptListeningSocket(
scoped_refptr<device::BluetoothSocket> socket,
const device::BluetoothUUID& uuid) {
DCHECK_CURRENTLY_ON(kThreadId);
if (socket_.get()) {
socket_->Disconnect(base::DoNothing());
}
socket_ = socket;
device_address_ = "";
uuid_ = uuid;
connected_ = false;
}
void BluetoothApiSocket::Disconnect(base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(kThreadId);
if (!socket_.get()) {
std::move(callback).Run();
return;
}
connected_ = false;
socket_->Disconnect(std::move(callback));
socket_.reset();
}
bool BluetoothApiSocket::IsPersistent() const {
DCHECK_CURRENTLY_ON(kThreadId);
return persistent_;
}
void BluetoothApiSocket::Receive(int count,
ReceiveCompletionCallback success_callback,
ErrorCompletionCallback error_callback) {
DCHECK_CURRENTLY_ON(kThreadId);
if (!socket_.get() || !IsConnected()) {
std::move(error_callback)
.Run(BluetoothApiSocket::kNotConnected, kSocketNotConnectedError);
return;
}
socket_->Receive(
count, std::move(success_callback),
base::BindOnce(&OnSocketReceiveError, std::move(error_callback)));
}
// static
void BluetoothApiSocket::OnSocketReceiveError(
ErrorCompletionCallback error_callback,
device::BluetoothSocket::ErrorReason reason,
const std::string& message) {
DCHECK_CURRENTLY_ON(kThreadId);
BluetoothApiSocket::ErrorReason error_reason =
BluetoothApiSocket::kSystemError;
switch (reason) {
case device::BluetoothSocket::kIOPending:
error_reason = BluetoothApiSocket::kIOPending;
break;
case device::BluetoothSocket::kDisconnected:
error_reason = BluetoothApiSocket::kDisconnected;
break;
case device::BluetoothSocket::kSystemError:
error_reason = BluetoothApiSocket::kSystemError;
break;
}
std::move(error_callback).Run(error_reason, message);
}
void BluetoothApiSocket::Send(scoped_refptr<net::IOBuffer> buffer,
int buffer_size,
SendCompletionCallback success_callback,
ErrorCompletionCallback error_callback) {
DCHECK_CURRENTLY_ON(kThreadId);
if (!socket_.get() || !IsConnected()) {
std::move(error_callback)
.Run(BluetoothApiSocket::kNotConnected, kSocketNotConnectedError);
return;
}
socket_->Send(buffer, buffer_size, std::move(success_callback),
base::BindOnce(&OnSocketSendError, std::move(error_callback)));
}
// static
void BluetoothApiSocket::OnSocketSendError(
ErrorCompletionCallback error_callback,
const std::string& message) {
DCHECK_CURRENTLY_ON(kThreadId);
std::move(error_callback).Run(BluetoothApiSocket::kSystemError, message);
}
void BluetoothApiSocket::Accept(AcceptCompletionCallback success_callback,
ErrorCompletionCallback error_callback) {
DCHECK_CURRENTLY_ON(kThreadId);
if (!socket_.get() || IsConnected()) {
std::move(error_callback)
.Run(BluetoothApiSocket::kNotListening, kSocketNotListeningError);
return;
}
socket_->Accept(
std::move(success_callback),
base::BindOnce(&OnSocketAcceptError, std::move(error_callback)));
}
// static
void BluetoothApiSocket::OnSocketAcceptError(
ErrorCompletionCallback error_callback,
const std::string& message) {
DCHECK_CURRENTLY_ON(kThreadId);
std::move(error_callback).Run(BluetoothApiSocket::kSystemError, message);
}
} // namespace extensions