summaryrefslogtreecommitdiffstats
path: root/chromeos/dbus/fake_bluetooth_device_client.cc
diff options
context:
space:
mode:
authorkeybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-09 03:49:18 +0000
committerkeybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-09 03:49:18 +0000
commite882d2cdf5ed5337d68f2b32ba0f885725ca8b3f (patch)
treec4ca06e4ad129b16aa1f04753db7ac4e98a55240 /chromeos/dbus/fake_bluetooth_device_client.cc
parentdc5d179b1e34c9147630adc9d20e43e7986f7feb (diff)
downloadchromium_src-e882d2cdf5ed5337d68f2b32ba0f885725ca8b3f.zip
chromium_src-e882d2cdf5ed5337d68f2b32ba0f885725ca8b3f.tar.gz
chromium_src-e882d2cdf5ed5337d68f2b32ba0f885725ca8b3f.tar.bz2
Bluetooth: Profile support for Chrome OS
Implement support for the BluetoothProfile API for the BlueZ 5.x stack on Chrome OS, including BluetoothSocket support. BUG=229636 TEST=device_unittests Review URL: https://chromiumcodereview.appspot.com/14487002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199095 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/dbus/fake_bluetooth_device_client.cc')
-rw-r--r--chromeos/dbus/fake_bluetooth_device_client.cc153
1 files changed, 151 insertions, 2 deletions
diff --git a/chromeos/dbus/fake_bluetooth_device_client.cc b/chromeos/dbus/fake_bluetooth_device_client.cc
index 4d3e189..b1ed840 100644
--- a/chromeos/dbus/fake_bluetooth_device_client.cc
+++ b/chromeos/dbus/fake_bluetooth_device_client.cc
@@ -4,6 +4,11 @@
#include "chromeos/dbus/fake_bluetooth_device_client.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
#include <algorithm>
#include <map>
#include <string>
@@ -12,14 +17,19 @@
#include "base/bind.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/stl_util.h"
+#include "base/threading/worker_pool.h"
#include "base/time.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_bluetooth_adapter_client.h"
#include "chromeos/dbus/fake_bluetooth_agent_manager_client.h"
#include "chromeos/dbus/fake_bluetooth_agent_service_provider.h"
#include "chromeos/dbus/fake_bluetooth_input_client.h"
+#include "chromeos/dbus/fake_bluetooth_profile_manager_client.h"
+#include "chromeos/dbus/fake_bluetooth_profile_service_provider.h"
+#include "dbus/file_descriptor.h"
#include "dbus/object_path.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
@@ -28,6 +38,30 @@ namespace {
// Default interval between simulated events.
const int kSimulationIntervalMs = 750;
+
+void SimulatedProfileSocket(int fd) {
+ // Simulate a server-side socket of a profile; read data from the socket,
+ // write it back, and then close.
+ char buf[1024];
+ ssize_t len;
+ ssize_t count;
+
+ len = read(fd, buf, sizeof buf);
+ if (len < 0) {
+ close(fd);
+ return;
+ }
+
+ count = len;
+ len = write(fd, buf, count);
+ if (len < 0) {
+ close(fd);
+ return;
+ }
+
+ close(fd);
+}
+
}
namespace chromeos {
@@ -267,7 +301,63 @@ void FakeBluetoothDeviceClient::ConnectProfile(
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "ConnectProfile: " << object_path.value() << " " << uuid;
- error_callback.Run(kNoResponseError, "");
+
+ FakeBluetoothProfileManagerClient* fake_bluetooth_profile_manager_client =
+ static_cast<FakeBluetoothProfileManagerClient*>(
+ DBusThreadManager::Get()->
+ GetExperimentalBluetoothProfileManagerClient());
+ FakeBluetoothProfileServiceProvider* profile_service_provider =
+ fake_bluetooth_profile_manager_client->GetProfileServiceProvider(uuid);
+ if (profile_service_provider == NULL) {
+ error_callback.Run(kNoResponseError, "Missing profile");
+ return;
+ }
+
+ // Make a socket pair of a compatible type with the type used by Bluetooth;
+ // spin up a thread to simulate the server side and wrap the client side in
+ // a D-Bus file descriptor object.
+ int socket_type = SOCK_STREAM;
+ if (uuid == FakeBluetoothProfileManagerClient::kL2capUuid)
+ socket_type = SOCK_SEQPACKET;
+
+ int fds[2];
+ if (socketpair(AF_UNIX, socket_type, 0, fds) < 0) {
+ error_callback.Run(kNoResponseError, "socketpair call failed");
+ return;
+ }
+
+ int args;
+ args = fcntl(fds[1], F_GETFL, NULL);
+ if (args < 0) {
+ error_callback.Run(kNoResponseError, "failed to get socket flags");
+ return;
+ }
+
+ args |= O_NONBLOCK;
+ if (fcntl(fds[1], F_SETFL, args) < 0) {
+ error_callback.Run(kNoResponseError, "failed to set socket non-blocking");
+ return;
+ }
+
+ base::WorkerPool::GetTaskRunner(false)->PostTask(
+ FROM_HERE,
+ base::Bind(&SimulatedProfileSocket,
+ fds[0]));
+
+ scoped_ptr<dbus::FileDescriptor> fd(new dbus::FileDescriptor(fds[1]));
+
+ // Post the new connection to the service provider.
+ ExperimentalBluetoothProfileServiceProvider::Delegate::Options options;
+
+ profile_service_provider->NewConnection(
+ object_path,
+ fd.Pass(),
+ options,
+ base::Bind(&FakeBluetoothDeviceClient::ConnectionCallback,
+ base::Unretained(this),
+ object_path,
+ callback,
+ error_callback));
}
void FakeBluetoothDeviceClient::DisconnectProfile(
@@ -276,7 +366,25 @@ void FakeBluetoothDeviceClient::DisconnectProfile(
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "DisconnectProfile: " << object_path.value() << " " << uuid;
- error_callback.Run(kNoResponseError, "");
+
+ FakeBluetoothProfileManagerClient* fake_bluetooth_profile_manager_client =
+ static_cast<FakeBluetoothProfileManagerClient*>(
+ DBusThreadManager::Get()->
+ GetExperimentalBluetoothProfileManagerClient());
+ FakeBluetoothProfileServiceProvider* profile_service_provider =
+ fake_bluetooth_profile_manager_client->GetProfileServiceProvider(uuid);
+ if (profile_service_provider == NULL) {
+ error_callback.Run(kNoResponseError, "Missing profile");
+ return;
+ }
+
+ profile_service_provider->RequestDisconnection(
+ object_path,
+ base::Bind(&FakeBluetoothDeviceClient::DisconnectionCallback,
+ base::Unretained(this),
+ object_path,
+ callback,
+ error_callback));
}
void FakeBluetoothDeviceClient::Pair(
@@ -920,4 +1028,45 @@ void FakeBluetoothDeviceClient::SimulateKeypress(
}
}
+void FakeBluetoothDeviceClient::ConnectionCallback(
+ const dbus::ObjectPath& object_path,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ ExperimentalBluetoothProfileServiceProvider::Delegate::Status status) {
+ VLOG(1) << "ConnectionCallback: " << object_path.value();
+
+ if (status ==
+ ExperimentalBluetoothProfileServiceProvider::Delegate::SUCCESS) {
+ callback.Run();
+ } else if (status ==
+ ExperimentalBluetoothProfileServiceProvider::Delegate::CANCELLED) {
+ // TODO(keybuk): tear down this side of the connection
+ error_callback.Run(bluetooth_adapter::kErrorFailed, "Canceled");
+ } else if (status ==
+ ExperimentalBluetoothProfileServiceProvider::Delegate::REJECTED) {
+ // TODO(keybuk): tear down this side of the connection
+ error_callback.Run(bluetooth_adapter::kErrorFailed, "Rejected");
+ }
+}
+
+void FakeBluetoothDeviceClient::DisconnectionCallback(
+ const dbus::ObjectPath& object_path,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback,
+ ExperimentalBluetoothProfileServiceProvider::Delegate::Status status) {
+ VLOG(1) << "DisconnectionCallback: " << object_path.value();
+
+ if (status ==
+ ExperimentalBluetoothProfileServiceProvider::Delegate::SUCCESS) {
+ // TODO(keybuk): tear down this side of the connection
+ callback.Run();
+ } else if (status ==
+ ExperimentalBluetoothProfileServiceProvider::Delegate::CANCELLED) {
+ error_callback.Run(bluetooth_adapter::kErrorFailed, "Canceled");
+ } else if (status ==
+ ExperimentalBluetoothProfileServiceProvider::Delegate::REJECTED) {
+ error_callback.Run(bluetooth_adapter::kErrorFailed, "Rejected");
+ }
+}
+
} // namespace chromeos